সি-তে কোনও ফাইল রয়েছে কিনা তা যাচাই করার সর্বোত্তম উপায় কী?


436

কেবল ফাইলটি খোলার চেষ্টা করার চেয়ে আরও ভাল উপায় কি আছে?

int exists(const char *fname)
{
    FILE *file;
    if ((file = fopen(fname, "r")))
    {
        fclose(file);
        return 1;
    }
    return 0;
}

আমি মনে করি আমি অ্যাক্সেস পদ্ধতির উত্তর দেব, স্ট্যাট পদ্ধতিটি খুব যুক্তিসঙ্গত বিকল্প হওয়া সত্ত্বেও অ্যাক্সেসটি কাজটি সম্পন্ন করে।
ডেভ মার্শাল

1
আপনি কি সত্যিই কেবল অস্তিত্ব পরীক্ষা করতে চান? অথবা আপনি কি পরীক্ষা করতে চান এবং যদি ফাইলটি ইতিমধ্যে বিদ্যমান না থাকে তবে লিখুন। যদি তা হয় তবে নীচে আমার উত্তরটি দেখুন, এমন কোনও সংস্করণের জন্য যা জাতি শর্তে ভুগছে না।
ড্যান লেন্সকি 17

6
আমি দেখতে পাচ্ছি না - এই ফপেন / এফক্লোজ উপায়টি কী?
জোহানেস স্কাউব -

16
@ জোহানেস শ্যাব-লিটব: fopen()/ fclose()পদ্ধতির সাথে একটি ভুল যা হ'ল এটি উপস্থিত থাকলেও আপনি পড়ার জন্য কোনও ফাইল খুলতে পারবেন না। উদাহরণস্বরূপ, /dev/kmemবিদ্যমান, তবে বেশিরভাগ প্রক্রিয়া এমনকি এটি পড়ার জন্য খুলতে পারে না। /etc/shadowএ জাতীয় আর একটি ফাইল। অবশ্যই, উভয় stat()এবং access()ফাইল ধারণকারী ডিরেক্টরিতে অ্যাক্সেস করতে সক্ষম হওয়ার উপর নির্ভর করে; আপনি যদি এটি না করতে পারেন তবে সমস্ত বেট বন্ধ রয়েছে (ফাইল ধারণকারী ডিরেক্টরিতে অনুমতি চালানোর অনুমতি নেই)।
জোনাথন লেফলার

1
if (file = fopen(fname, "r"))একটি সতর্কতা দেবে। যদি বিবৃতিটির ভিতরে বক্তব্যটির চারপাশে প্রথম বন্ধনী ব্যবহার করুনif ((file = fopen(fname, "r")))
জোয়াকিম

উত্তর:


595

দেখুন access()ফাংশন, পাওয়া unistd.h। আপনি আপনার ফাংশনটি এর সাথে প্রতিস্থাপন করতে পারেন

if( access( fname, F_OK ) != -1 ) {
    // file exists
} else {
    // file doesn't exist
}

এছাড়াও আপনি ব্যবহার করতে পারেন R_OK, W_OKএবং X_OKস্থানে F_OKপঠিত অনুমতি লেখার অনুমতি যাচাই করার এবং বরং অস্তিত্বের চেয়ে অনুমতি (যথাক্রমে) চালানো এবং আপনি তাদের কোন একসঙ্গে করতে পারেন অথবা (অর্থাত উভয় পঠিত জন্য পরীক্ষা এবং লেখার অনুমতি ব্যবহার R_OK|W_OK)

আপডেট : নোট করুন যে উইন্ডোজটিতে আপনি W_OKলেখার অনুমতিটির জন্য নির্ভরযোগ্যভাবে পরীক্ষা করতে পারবেন না , যেহেতু অ্যাক্সেস ফাংশনটি DACLs কে বিবেচনা করে না। access( fname, W_OK )0 (সাফল্য) ফিরতে পারে কারণ ফাইলটিতে কেবল পঠনযোগ্য এট্রিবিউট সেট নেই, তবে আপনার কাছে এখনও ফাইলটিতে লেখার অনুমতি নেই।


67
পসিক্স একটি আইএসও স্ট্যান্ডার্ড; এটি অ্যাক্সেস সংজ্ঞায়িত করে ()। সি আরেকটি আইএসও স্ট্যান্ডার্ড; এটা না.
জোনাথন লেফলার

16
অ্যাক্সেস () এর সাথে সম্পর্কিত সমস্যাগুলি রয়েছে। অ্যাক্সেস () ব্যবহারের পরে এবং পরে আপনি যা কিছু করেন তার মধ্যে দুর্বলতার উইন্ডো রয়েছে একটি টেকটিউ (চেকের সময়, ব্যবহারের সময়) window [... চালিয়ে যেতে ...]
জোনাথন লেফলার

23
[... চালিয়ে যাওয়া ...] বরং আরও স্পষ্টতই, পসিক্স সিস্টেমে অ্যাক্সেস () কার্যকর ইউআইডি এবং কার্যকর জিআইডি না হয়ে আসল ইউআইডি এবং আসল জিআইডি কিনা তা পরীক্ষা করে। এটি কেবল নির্ধারিত বা নির্ধারিত প্রোগ্রামগুলির জন্যই গুরুত্বপূর্ণ, তবে এটি তীব্রভাবে গুরুত্বপূর্ণ কারণ এটি 'ভুল' উত্তর দিতে পারে।
জোনাথন লেফলার

3
access()আমার কোডটি ভেঙে যাওয়ার কারণটি অনুসন্ধান করার সময় আমি এই প্রশ্নটি ছড়িয়ে দিয়েছি। আমি ডিভিসি ++ থেকে কোডব্লকগুলিতে চলে এসেছি এবং এটি কাজ করা বন্ধ করে দিয়েছে। সুতরাং, এটি অবর্ণনীয় নয়; @ লেফ্লারকে আরও +1 করুন।
বেন

11
বেশিরভাগ সময়, হ্যাঁ ( access()কোনও ফাইলের অস্তিত্ব পরীক্ষা করার জন্য এটি ব্যবহার করা ঠিক আছে ), তবে কোনও এসইউডি বা এসজিআইডি প্রোগ্রামেও এটি ভুল হতে পারে। যদি পরীক্ষিত ফাইলটি এমন কোনও ডিরেক্টরিতে থাকে যা প্রকৃত ইউআইডি বা বাস্তব জিআইডি অ্যাক্সেস করতে পারে না, উপস্থিত access()থাকতে পারে এমন কোনও ফাইলের প্রতিবেদন করতে পারে। রহস্যময় এবং অসম্ভব? হ্যাঁ.
জোনাথন লেফলার

116

এটি ব্যবহার করুন stat:

#include <sys/stat.h>   // stat
#include <stdbool.h>    // bool type

bool file_exists (char *filename) {
  struct stat   buffer;   
  return (stat (filename, &buffer) == 0);
}

এবং এটিকে কল করুন:

#include <stdio.h>      // printf

int main(int ac, char **av) {
    if (ac != 2)
        return 1;

    if (file_exists(av[1]))
        printf("%s exists\n", av[1]);
    else
        printf("%s does not exist\n", av[1]);

    return 0;
}

4
@ লুডভিগানোরিন: এই জাতীয় সিস্টেমে সম্ভাবনাগুলিও রয়েছে যেগুলিরও access()সমস্যা রয়েছে access()এবং stat()বড় ফাইলগুলি তৈরি করতে ও কাজ করার জন্য বিকল্প রয়েছে (2 জিবি এর চেয়েও বড়)।
জোনাথন লেফলার

14
আপনারা কেউ 2 জিবি-র পরে ব্যর্থতা সম্পর্কিত ডকুমেন্টেশনের দিকে ইঙ্গিত করতে পারবেন? এছাড়াও, এই ধরনের ক্ষেত্রে বিকল্প কি?
চাঁকিতস

@ statজোনাথনলফলার একই টেকটিউ দুর্বলতায় ভুগছেন না access? (এটি আমার পক্ষে পরিষ্কার নয় যে এটি আরও ভাল হবে))
টেলিম্যাকাস

9
উভয় stat()এবং access()টেকটিও দুর্বলতায় ভুগছেন (তাই হয় lstat()তবে fstat()নিরাপদ)। এটি ফাইলের উপস্থিতি বা অনুপস্থিতির ভিত্তিতে আপনি কী করতে যাচ্ছেন তা নির্ভর করে। সঠিক বিকল্পগুলির সাথে ব্যবহার করা open()সমস্যাগুলির সাথে মোকাবিলা করার সর্বোত্তম উপায় তবে সঠিক বিকল্পগুলি তৈরি করা জটিল y ইএএফপি (পারফরমেন্সের চেয়ে ক্ষমা চাওয়ার পক্ষে সহজ) এবং এলবিওয়াইএল (আপনি আগে লাফ দেওয়ার আগে দেখুন) এর জন্য আলোচনা দেখুন - উদাহরণস্বরূপ জাভাতে এলবিওয়াইএল বনাম ইএএফপি দেখুন ।
জোনাথন লেফলার

87

সাধারণত আপনি যখন কোনও ফাইল উপস্থিত থাকেন কিনা তা পরীক্ষা করতে চান, কারণ এটি না থাকলে আপনি সেই ফাইলটি তৈরি করতে চান । আপনি যদি সেই ফাইলটি তৈরি করতে না চান তবে গ্রিম পেরোর জবাব ভাল, তবে যদি আপনি এটি করেন তবে এটি একটি জাতি শর্তের পক্ষে ঝুঁকিপূর্ণ: অন্য কোনও প্রক্রিয়া আপনার উপস্থিতির মধ্যে যাচাই করে ফাইলটি তৈরি করতে পারে এবং আপনি এটি লিখতে আসলে এটি খোলেন । (হাসবেন না ... এটি তৈরি করা ফাইলটি যদি একটি সিমিলিংক হত তবে এটির নিরাপত্তার খারাপ প্রভাব থাকতে পারে !)

আপনি যদি অস্তিত্বের জন্য যাচাই করতে চান এবং ফাইলটি উপস্থিত না থাকলে এটি তৈরি করতে চান , পারমাণবিকভাবে যাতে কোনও রেসের শর্ত না থাকে তবে এটি ব্যবহার করুন:

#include <fcntl.h>
#include <errno.h>

fd = open(pathname, O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0) {
  /* failure */
  if (errno == EEXIST) {
    /* the file already existed */
    ...
  }
} else {
  /* now you can use the file */
}

8
আপনি যদি O_CREAT ব্যবহার করতে চলেছেন তবে () খোলার জন্য আপনার তৃতীয় যুক্তি হিসাবে মোড (অনুমতি) সরবরাহ করতে হবে। O_TRUNC বা O_EXCL বা O_APPEND ব্যবহার করা উচিত কিনা তাও বিবেচনা করুন।
জোনাথন লেফলার

6
জোনাথন লেফলার ঠিক বলেছেন, এই উদাহরণে O_EXCL লিখিত হিসাবে কাজ করা দরকার।
র‌্যান্ডি প্রক্টর

6
এছাড়াও, আপনাকে মোডটি তৃতীয় যুক্তি হিসাবে উল্লেখ করতে হবে: খুলুন (লক করুন, ও_ক্র্যাট | ও_আরওয়ালি | ও_এক্সসিএল, এস_আইআরএসআর | এস_আইডাব্লু)
অ্যান্ড্রু কুক

4
এটি লক্ষ করা উচিত যে এটি কেবলমাত্র পজিআইএক্স অনুবর্তী হিসাবে সিস্টেম সিস্টেম নিরাপদ; বিশেষত, এনএফএসের পুরানো সংস্করণগুলিতে খুব রেস শর্ত রয়েছে O_EXCL এড়াতে হবে! এখানে একটি কার্যবিবরণী রয়েছে, যা লিঙ্কযুক্ত open(2)(লিনাক্সে; আপনার ওএস এর ম্যান পৃষ্ঠাগুলি পরিবর্তিত হতে পারে), তবে এটি বরং কুরুচিপূর্ণ এবং দূষিত আক্রমণকারীটির বিরুদ্ধে প্রতিরোধী নাও হতে পারে।
কেভিন

নোট করুন যে FILE*এটির সাথে এটি ব্যবহার করার জন্য, আপনাকে fdopen(fd,"flags")একটি জেনারেট করার জন্য পসিক্স পদ্ধতিটি ব্যবহার করতে হবেFILE*
জেম টেলর

32

হ্যাঁ. ব্যবহার stat()। ম্যান পেজ দেখুন stat(2)

stat()ফাইলটি উপস্থিত না থাকলে ব্যর্থ হবে, অন্যথায় সম্ভবত সফল হয়। যদি এটি বিদ্যমান থাকে তবে আপনার যে ডিরেক্টরিটি রয়েছে সেখানে এটির কোনও পাঠ্য অ্যাক্সেস নেই, এটি ব্যর্থও হবে তবে সেক্ষেত্রে যে কোনও পদ্ধতি ব্যর্থ হবে (অ্যাক্সেসের অধিকার অনুসারে আপনি যে ডিরেক্টরিটি দেখতে পাচ্ছেন না সেটিকে আপনি কীভাবে পরীক্ষা করতে পারেন? সহজভাবে, আপনি পারবেন না)।

ওহ, অন্য কেউ যেমন উল্লেখ করেছেন, আপনি এটিও ব্যবহার করতে পারেন access()। তবে আমি পছন্দ করি stat(), যেমন ফাইলটি বিদ্যমান আছে তা অবিলম্বে আমাকে প্রচুর দরকারী তথ্য (এটি শেষ কবে আপডেট করা হয়েছিল, এটি কত বড়, মালিক এবং / অথবা গ্রুপ যে ফাইলটির মালিক, অ্যাক্সেস অনুমতিগুলি ইত্যাদি) get


5
অ্যাক্সেস প্রিফার করা থাকে যদি আপনার কেবলমাত্র ফাইলের উপস্থিতি আছে কিনা তা জানতে হবে। আপনার যদি অতিরিক্ত সমস্ত তথ্যের প্রয়োজন না হয় তবে স্ট্যাটাস () এর একটি বৃহত্তর শোনা যাবে।
মার্টিন বেকেট

4
আসলে আমি যখন এলএস-কমান্ড ব্যবহার করে একটি ডিরেক্টরি তালিকাবদ্ধ করি তখন এটি উপস্থিত প্রতিটি ফাইলের জন্য স্ট্যাটকে কল করে এবং যে চলমান এলএসের একটি বড় ওভারহেড থাকে তা আমার কাছে বেশ নতুন। আসলে আপনি হাজার হাজার ফাইল সহ ডিরেক্টরিতে এলএস চালাতে পারেন এবং এটি এক সেকেন্ডের ভগ্নাংশে ফিরে আসে।
মেকি

2
@ মেক্কি: হার্ডলিঙ্কগুলিকে সমর্থন করে এমন সিস্টেমে অ্যাক্সেসের তুলনায় স্ট্যাটের ননজারো অতিরিক্ত ওভারহেড রয়েছে। এটি কারণ অ্যাক্সেস কেবল ডিরেক্টরি এন্ট্রি দেখতে হয়, যখন স্ট্যাটটি পাশাপাশি ইনোডটিও দেখতে হয়। খারাপ অনুসন্ধানের সময় (যেমন টেপ) সহ স্টোরেজ ডিভাইসে, পার্থক্যটি উল্লেখযোগ্য হতে পারে যেহেতু ডিরেক্টরি এন্ট্রি এবং ইনোড একে অপরের পাশে থাকার সম্ভাবনা কম।
কেভিন

3
@ কেভিন আপনি যদি কেবল এটিতে F_OK পাস না করেন তবে কোনও access()ফাইলের ফাইল অ্যাক্সেসের অনুমতিগুলি পরীক্ষা করে এটি এ ফাইলটির জন্য ইনোডে সঞ্চিত থাকে এবং এটির ডিরেক্টরি এন্ট্রিতে থাকে না (কমপক্ষে সমস্ত ফাইল সিস্টেমের ক্ষেত্রে যা ইনোডের মতো কাঠামোযুক্ত) । সুতরাং access()ইনোডটি যেভাবে অ্যাক্সেস করতে হবে ঠিক একইভাবে stat()প্রবেশ করতে হবে। সুতরাং আপনি যা বলছেন তা যদি সত্য হয় তবে যদি আপনি কোনও অনুমতি পরীক্ষা না করেন! এবং আসলে কিছু সিস্টেমে access()এমনকি উপরেও প্রয়োগ করা হয় stat()(যেমন GNU হার্টে গ্লিবসি এটি সেভাবে করে), সুতরাং প্রথম স্থানে কোনও গ্যারান্টি নেই।
মক্কি

@ মেক্কি: অনুমতি পরীক্ষা করার বিষয়ে কে কিছু বলেছে ? আমি বিশেষত এফ_ওকে নিয়ে কথা বলছিলাম। এবং হ্যাঁ, কিছু সিস্টেম খারাপভাবে প্রয়োগ করা হয়নি। অ্যাক্সেস কমপক্ষে প্রতিটি ক্ষেত্রে স্ট্যাট হিসাবে দ্রুত হবে এবং কিছু সময় দ্রুত হতে পারে।
কেভিন

9
FILE *file;
    if((file = fopen("sample.txt","r"))!=NULL)
        {
            // file exists
            fclose(file);
        }
    else
        {
            //File not found, no memory leak since 'file' == NULL
            //fclose(file) would cause an error
        }

1
এটি কি স্মৃতি ফাঁসির কারণ হবে না? ফাইলটি উপস্থিত থাকলে আপনি কখনও এটি বন্ধ করবেন না।
LegionMammal978

1
এটি একটি ভাল, সহজ পদ্ধতি। আপনি যদি উইন্ডোজ এমএসভিসিতে থাকেন তবে পরিবর্তে এটি ব্যবহার করুন: (fopen_s(file, "sample.txt", "r"))যেহেতু অবচয় fopen()বিবেচিত (বা অবচয় ত্রুটিগুলি অক্ষম করুন, তবে এটি প্রস্তাবিত নয়)।
নিকস

15
fopen()স্ট্যান্ডার্ড সি, এটি কোথাও যাচ্ছে না। এটি মাইক্রোসফ্ট দ্বারা কেবল "অবচয়"। fopen_s()আপনি প্ল্যাটফর্ম-নির্দিষ্ট, অ-বহনযোগ্য কোড না চাইলে ব্যবহার করবেন না ।
অ্যান্ড্রু হেনেল

কোন কিছুর জন্য fclose () কল করা হচ্ছে? প্রথমে ভেরিয়েবল 'ফাইল' বরাদ্দ করা দরকার!
জেনিক্স

1
এখানে চলক 'ফাইল' এর একটি আবর্জনার মান রয়েছে has কেন এটি প্রথম স্থানে বন্ধ করতে বিরক্ত করবেন? আপনি কেবল 'fclose (SOME_RANDOM_ADDRESS)' কল করছেন; .. ..
জেনিক্স

6

ভিজ্যুয়াল সি ++ সহায়তা থেকে, আমি যেতে চাই

/* ACCESS.C: This example uses _access to check the
 * file named "ACCESS.C" to see if it exists and if
 * writing is allowed.
 */

#include  <io.h>
#include  <stdio.h>
#include  <stdlib.h>

void main( void )
{
   /* Check for existence */
   if( (_access( "ACCESS.C", 0 )) != -1 )
   {
      printf( "File ACCESS.C exists\n" );
      /* Check for write permission */
      if( (_access( "ACCESS.C", 2 )) != -1 )
         printf( "File ACCESS.C has write permission\n" );
   }
}

এর মোডের মানগুলিও মূল্যবান :_access(const char *path,int mode)

  • 00: শুধুমাত্র অস্তিত্ব

  • 02: অনুমতি লিখুন

  • 04: অনুমতি পড়ুন

  • 06: অনুমতি পড়ুন এবং লিখুন

যেহেতু আপনার fopenফাইলগুলি বিদ্যমান পরিস্থিতিতে ব্যর্থ হতে পারে তবে অনুরোধ অনুসারে খোলা যায় নি।

সম্পাদনা: সবেমাত্র মক্কির পোস্টটি পড়ুন। stat()দেখতে যাওয়ার মতো সুন্দর উপায় দেখাচ্ছে না। হো হাম।


অ্যাক্সেস প্রিফার করা থাকে যদি আপনার কেবলমাত্র ফাইলের উপস্থিতি আছে কিনা তা জানতে হবে। স্ট্যাটাস () এর একটি বৃহত্তর শোনা যায়।
মার্টিন বেকেট

4

আপনি রিয়েলপথ () ফাংশন ব্যবহার করতে পারেন।

resolved_file = realpath(file_path, NULL);
if (!resolved_keyfile) {
   /*File dosn't exists*/
   perror(keyfile);
   return -1;
}

3

আমি মনে করি যে অ্যাক্সেস () ফাংশনটি পাওয়া যায় unistd.hএটি একটি ভাল পছন্দ Linux(আপনি স্ট্যাট ব্যবহার করতে পারেন )।

আপনি এটি এর মতো ব্যবহার করতে পারেন:

#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>

void fileCheck(const char *fileName);

int main (void) {
    char *fileName = "/etc/sudoers";

    fileCheck(fileName);
    return 0;
}

void fileCheck(const char *fileName){

    if(!access(fileName, F_OK )){
        printf("The File %s\t was Found\n",fileName);
    }else{
        printf("The File %s\t not Found\n",fileName);
    }

    if(!access(fileName, R_OK )){
        printf("The File %s\t can be read\n",fileName);
    }else{
        printf("The File %s\t cannot be read\n",fileName);
    }

    if(!access( fileName, W_OK )){
        printf("The File %s\t it can be Edited\n",fileName);
    }else{
        printf("The File %s\t it cannot be Edited\n",fileName);
    }

    if(!access( fileName, X_OK )){
        printf("The File %s\t is an Executable\n",fileName);
    }else{
        printf("The File %s\t is not an Executable\n",fileName);
    }
}

এবং আপনি নিম্নলিখিত আউটপুট পান:

The File /etc/sudoers    was Found
The File /etc/sudoers    cannot be read
The File /etc/sudoers    it cannot be Edited
The File /etc/sudoers    is not an Executable
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.