запись файлов и каталогов с использованием C++

Я работаю над программой, которая создает 2000 каталогов и помещает файл в каждый (всего файл размером 10 КБ или около того). Я использую mkdir для создания каталогов и ofstream (я также пробовал fopen) для записи файлов на твердотельный накопитель (я провожу тесты скорости для сравнения).

Когда я запускаю код, каталоги создаются нормально, но файлы перестают записываться после того, как 1000 или около того были записаны. Я пытался поставить задержку перед каждой записью на случай, если это была какая-то перегрузка, а также пытался использовать fopen вместо ofstream, но он всегда останавливает запись файлов около 1000-й отметки файла.

это код, который записывает файлы и завершает работу, сообщая мне, в каком файле произошел сбой.

fsWriteFiles.open(path, ios::app); 
if(!fsWriteFiles.is_open()) 
{
   cout << "Fail at point: " << filecount  << endl; 
   return 1;
}
fsWriteFiles << filecontent;
fsWriteFiles.close();

Кто-нибудь сталкивался с этим или есть теории?

Вот полный код: Этот код создает 2-значный шестнадцатеричный каталог из случайного числа, затем 4-значный шестнадцатеричный каталог из случайного числа, а затем сохраняет файл в этом каталоге. Он завершается с ошибкой в ​​​​точке (я добавил cout) после записи 1000 файлов. Это указывает на то, что он не может создать файл, но должен уже проверить, что файл не существует. Иногда он терпит неудачу на 0, попав во вторую строку снизу (предложение else для уже существующего файла). любая помощь приветствуется, я чувствую, что это связано с файлами, которые я пытаюсь создать, уже существующими, но которые каким-то образом ускользнули от моей проверки существования файла. Есть ли способ получить сообщение об ошибке при неудачной попытке создания файла?

int main()
{
  char charpart1[3] = "";
  char charpart3[5] = "";

  char path[35] = "";
  int randomStore = 0;

  //Initialize random seed
  srand(time(NULL));
  struct stat buffer ;

  //Create output file streams
  ofstream fsWriteFiles;    
  ifstream checkforfile;

  //Loop X times
  int dircount = 0;
  while(dircount < 2000)
  {
    path[0] = '\0'; //reset the char array that holds the path

    randomStore = rand() % 255;
    sprintf(charpart1, "%.2x", randomStore);
    randomStore = rand() % 65535;
    sprintf(charpart3, "%.4x", randomStore);

    //Check if top level dir exists, create if not
    strcat(path, "fastdirs/");
    strcat(path, charpart1);
    DIR *pdir=opendir(path);

    //If the dir does not exist create it with read/write/search permissions for owner 
    // and group, and with read/search permissions for others
    if(!pdir)
      mkdir(path,  S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);

    //Check if 3rd level dir exists, create if not
    strcat(path, "/");
    strcat(path, charpart3);
    DIR *pdir3=opendir(path);

    if(!pdir3)
      mkdir(path,  S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);

    strcat(path, "/");
    strcat(path, charpart3);
    strcat(path, ".txt");
    //Write the file if it does not already exist
    checkforfile.open(path, fstream::in);

    if (checkforfile.is_open() != true)
    {
      fsWriteFiles.open(path, ios::app); 
      if(!fsWriteFiles.is_open()) 
      {
        cout << "Fail at point: " << dircount << "\n" << endl;
        return 1;
      }
      fsWriteFiles << "test";
      fsWriteFiles.flush();
      fsWriteFiles.close();

      dircount ++; //increment the file counter
    }
    else
    {
      cout << "ex";
      checkforfile.close();
    }
  } 
}

person Columbo    schedule 18.08.2009    source источник
comment
Просто догадка, как насчет форсирования флеша?   -  person kenny    schedule 18.08.2009
comment
возможно ли, что mkdir терпит неудачу? Вы проверили его возвращаемое значение? Может быть повреждение памяти, потенциально.   -  person Goz    schedule 18.08.2009
comment
спасибо Kenny & Goz, попробовал сбросить, но без изменений, также проверил, и каталог создается.   -  person Columbo    schedule 18.08.2009
comment
Пожалуйста, опубликуйте больше контекста - цикл, объявление fsWriteFiles и т. д. Это это поток, а не что-то еще, не так ли?   -  person Roddy    schedule 18.08.2009


Ответы (5)


Вы открываете каталоги с помощью opendir(), но никогда не закрываете их с помощью Closedir() - я подозреваю, что там тоже есть ограничение на ресурсы.

person Community    schedule 18.08.2009
comment
Я потратил столько времени на переформатирование проклятого кода, чтобы прочитать его, что вы меня опередили! - person Roddy; 18.08.2009
comment
Я думаю, что это показывает ценность публикации АКТУАЛЬНОГО КОДА при задании вопроса о SO. - person ; 18.08.2009
comment
Да, в будущем я опубликую все это, а не только то, что я думаю, что ошибаюсь, еще раз спасибо - person Columbo; 18.08.2009
comment
Пожалуйста, пишите только то, что вы сначала считаете неправильным, чтобы я не тратил время зря, когда вы были правы. - person Dustin Getz; 18.08.2009

Вы закрываете файлы? Похоже, вы достигли предела дескриптора файла, который обычно равен 1024. Для простой проверки попробуйте «ulimit -n 4096» и снова запустите вашу программу.

person Gunther Piez    schedule 18.08.2009
comment
Это звучит как возможность. К сожалению, мне не разрешено использовать команду ulimit. Также я закрываю файл, я думал, что файлы закрываются недостаточно быстро, но я пробовал ждать перед каждым открытием, и это не помогло. спасибо за ваши предложения. - person Columbo; 18.08.2009
comment
@Columbo Вам не нужен ulimit. Чтобы проверить эту гипотезу, откройте 100 файлов, но НЕ закрывайте их ДО своего существующего кода. Затем посмотрите, произошел ли сбой раньше или нет. - person ; 18.08.2009
comment
проверено. Не закрыл первые 100 файлов и никаких изменений, все еще начинает сбой около 1000 записанных файлов. - person Columbo; 18.08.2009
comment
Это не годится для теста. Вам нужно открыть, но не закрыть 100 файлов, которые не являются частью вашего цикла, прежде чем вы начнете цикл, а затем посмотрите, сколько вы можете открыть в цикле при обычном закрытии. - person ; 18.08.2009
comment
Теперь я добавил цикл перед циклом, который вы можете видеть в опубликованном мной коде, который создает 100 новых файлов и не закрывает их. Все еще не работает (я редактирую свой исходный пост, чтобы показать весь код. - person Columbo; 18.08.2009

Я не вижу ничего явно неправильного в опубликованном коде, но вы не показали достаточного контекста, чтобы кто-то мог сильно помочь.

Однако я был бы счастливее, если бы вы использовали RAII для обеспечения закрытия файлов, используя конструктор/деструктор ofstream для выполнения открытия/закрытия: -

for (int i=0; i != MAX_FILES; ++i)
{     
  ofstream sWriteFiles(getFilePath(i), ios::app); 

  if (!fsWriteFiles.is_open()) 
  {
    cout << "Fail at point: " << filecount  << endl; 
    return 1;
  }

  fsWriteFiles << filecontent;
}

Да, вы «конструируете» потоковые объекты каждый раз в цикле, но я бы нашел этот код намного более удобным для сопровождения.

person Roddy    schedule 18.08.2009
comment
Судя по его коду, который не показывает цикл, это именно то, что он делает, с дополнительным (безвредным) вызовом close(). - person ; 18.08.2009
comment
@Neil - возможно - но я не удивлюсь, если его поток окажется вне цикла и будет повторно использован N раз. Начиная со «свежего» потока каждый раз, вы чувствуете себя немного чище. Мы также делаем предположение, что это класс ofstream, а не производный класс с неработающим методом закрытия. - person Roddy; 18.08.2009
comment
теперь я добавил оператор создания потока прямо над попыткой открытия - все еще сбой при той же цифре 1000 файлов if(!checkforfile.is_open()) { ofstream fsWriteFiles; fsWriteFiles.open(путь, ios::app); ... - person Columbo; 18.08.2009
comment
@Columbo: ПОЖАЛУЙСТА, ОТРЕдактируйте исходный пост, чтобы показать больше вашего НАСТОЯЩЕГО кода. Мы не можем догадаться, что вы написали. - person Roddy; 18.08.2009

просто хочу убедиться, что вы знаете о boost: :файловая система. Это может значительно упростить ваш код.

#include "boost/filesystem.hpp"   // includes all needed Boost.Filesystem declarations
#include <iostream>               // for std::cout
using boost::filesystem;          // for ease of tutorial presentation;
                                  //  a namespace alias is preferred practice in real code

path my_path( "some_dir/file.txt" );

remove_all( "foobar" );
create_directory( "foobar" );
ofstream file( "foobar/cheeze" );
file << "tastes good!\n";
file.close();
if ( !exists( "foobar/cheeze" ) )
  std::cout << "Something is rotten in foobar\n";
person Dustin Getz    schedule 18.08.2009
comment
Это выглядит очень интересно, я собираюсь проверить это. та Дастин. - person Columbo; 18.08.2009
comment
Boost — это C++, поэтому он может использовать dtors. Это спасет вас во многих случаях и, вероятно, спасло бы вас здесь. - person MSalters; 18.08.2009

У вас есть следующее:

char charpart1[3] = "";
randomStore = rand() % 255;
sprintf(charpart1, "%.2x", randomStore);

Вы хотели использовать формат «%.2f» вместо x? %.2x по-прежнему печатает «3ff3c083», что переполняет ваш буфер. Кроме того, вы, вероятно, захотите, чтобы charpart1 имел размер 5, а не 3, если вы переключитесь на %0.2f, потому что это записывает [0][.][2][3][\0] (например).

person Gabe    schedule 18.08.2009