закрыть файл с помощью fclose(), но файл все еще используется

У меня проблема с удалением/перезаписью файла с помощью моей программы, который также используется (читается) моей программой. Проблема, по-видимому, заключается в том, что из-за того, что моя программа считывает данные из файла (output.txt), она переводит файл в состояние «используется», что делает невозможным удаление или перезапись файла.

Я не понимаю, почему файл остается «используемым», потому что я закрываю файл после использования с помощью fclose();

это мой код:

bool bBool = true

while(bBool){
  //Run myprogram.exe tot generate (a new) output.txt

  //Create file pointer and open file
  FILE* pInputFile = NULL;
  pInputFile = fopen("output.txt", "r");
  //
  //then I do some reading using fscanf()
  //
  //And when I'm done reading I close the file using fclose()
  fclose(pInputFile);

  //The next step is deleting the output.txt
  if( remove( "output.txt" ) == -1 ){
    //ERROR
  }else{
    //Succesfull
  }
}

Я использую fclose(), чтобы закрыть файл, но файл продолжает использоваться моей программой до тех пор, пока моя программа не будет полностью закрыта.

Каково решение для освобождения файла, чтобы его можно было удалить/перезаписать?

На самом деле мой код не является бесконечным циклом; )

Заранее спасибо!

Марко

Обновить

Например, спросите часть моего кода, которая также генерирует файл «используется». Это не цикл, и эта функция вызывается из функции main();

Вот фрагмент кода:

int iShapeNr = 0;

void firstRun()
{
    //Run program that generates output.txt
    runProgram();

    //Open Shape data file
    FILE* pInputFile = NULL;
    int iNumber = 0;
    pInputFile = fopen("output.txt", "r");

    //Put all orientations of al detected shapes in an array
    int iShapeNr = 0;
    int iRotationBuffer[1024];//1024 is maximum detectable shapes, can be changed in RoboRealm
    int iXMinBuffer[1024];
    int iXMaxBuffer[1024];
    int iYMinBuffer[1024];
    int iYMaxBuffer[1024];

    while(feof(pInputFile) == 0){       
        for(int i=0;i<9;i++){
            fscanf(pInputFile, "%d", &iNumber);
            fscanf(pInputFile, ",");
            if(i == 1) {
                iRotationBuffer[iShapeNr] = iNumber;
            }
            if(i == 3){//xmin
                iXMinBuffer[iShapeNr] = iNumber;
            }
            if(i == 4){//xmax
                iXMaxBuffer[iShapeNr] = iNumber;
            }
            if(i == 5){//ymin
                iYMinBuffer[iShapeNr] = iNumber;
            }
            if(i == 6){//ymax
                iYMaxBuffer[iShapeNr] = iNumber;
            }
        }
        iShapeNr++;
    }
    fflush(pInputFile);
    fclose(pInputFile);

}

Цикл while анализирует файл. Output.txt содержит наборы из 9 переменных, количество наборов неизвестно, но всегда в наборах по 9.

output.txt может содержать, например: 0,1,2,3,4,5,6,7,8,8,7,6,5,4,1,2,3,0

обновление 2

код:

    void runProgram(){
    //Check if output.txt exists, if so delete it
    if(fileExists("output.txt") == 1){
        //Delete output.txt
        if( remove( "output2.txt" ) == -1 ){
            //errormessage
        }else{
            //succesfull
        }
    }   
    //start program
    ShellExecute( NULL, TEXT("open"), TEXT("program.exe"), NULL, NULL, SW_SHOWMAXIMIZED);

    while(fileExists("output.txt") == 0);

    //Close program
    int iCheck = system("taskkill /IM program.exe");
    if(iCheck != 0){
        //error could not shut down
    }
}

извините за использование pre снова, но я не понимаю форматирование этого сайта :(


person Marco    schedule 12.01.2011    source источник
comment
Используете ли вы strerror/perror для диагностики того, что пошло не так? Вы на какой ОС?   -  person Henno Brandsma    schedule 12.01.2011
comment
Вы уже пытались выполнить fflush() файл перед его закрытием()?   -  person Bart    schedule 12.01.2011
comment
@ Барт, в этом нет необходимости, flcose() позаботится об этом. @Marco, как говорит @Henno Brandsma, осмотрите errno и посмотрите, что там написано, это может дать вам некоторые подсказки. Кстати, это помечено как C++, почему вы не используете потоки ввода-вывода??   -  person Nim    schedule 12.01.2011
comment
Вам всегда нужно проверять возвращаемое значение fclose().   -  person Simone    schedule 12.01.2011
comment
Спасибо за эти быстрые ответы. Моя ОС - Windows XP (Pro). Я не пробовал fflush() из-за того, что говорит Ним. Я попытаюсь выяснить, что говорит errno. Я не очень хорошо разбираюсь в программировании на С++, поэтому выбрал этот метод. Как насчет потоков ввода-вывода? Какая разница?   -  person Marco    schedule 12.01.2011
comment
Пока он читает файл, нужно ли будет вызывать fflush в любом случае?   -  person Moo-Juice    schedule 12.01.2011
comment
@Simone это довольно бесполезно (если только не для отладки), потому что вы не можете сделать с этим ничего значимого. это как кидать из деструктора.   -  person Yakov Galka    schedule 12.01.2011
comment
Я попробовал fflush() перед битом fclose(), это не решило проблему.   -  person Marco    schedule 12.01.2011
comment
Не могли бы вы опубликовать код (если возможно, при необходимости обобщить), который находится между открытием и закрытием? Я заметил, что вы запускаете это в цикле. Это происходит на 1-й или последующей итерации?   -  person Moo-Juice    schedule 12.01.2011
comment
В моей программе есть первый раздел кода, который не находится в цикле, также есть часть fopen()/fclose(), но когда я запускаю только эту часть, происходит то же самое. Я постараюсь опубликовать эту часть кода.   -  person Marco    schedule 12.01.2011
comment
Обычно вы не можете удалить файл, только если он все еще открыт другим процессом, возможно, тем же самым, который создает файл output.txt, который вы пытаетесь прочитать. Нам абсолютно необходимо увидеть код.   -  person Mr.Gate    schedule 12.01.2011
comment
@Marco: Вы должны использовать кнопку {} вместо кнопки pre.   -  person Yakov Galka    schedule 12.01.2011
comment
Нет причин выполнять fflush() для файла, который вы только что читали. fflush() может быть вызван перед fclose() в вашей функции runProgram(). Что-то в моей голове подсказывает мне, что вы на самом деле запускаете другую программу, живя своей жизнью, для создания и загрузки файла output.txt. Итак ... вы, вероятно, попытаетесь удалить этот файл, пока он еще открыт программой, которая его создает, поскольку запуск программы можно выполнить, не дожидаясь завершения этой программы.   -  person Mr.Gate    schedule 12.01.2011
comment
@ybungalobill кажется, что ОП отлаживает, не так ли?   -  person Simone    schedule 12.01.2011
comment
@Mr.Gate: проблема не в этом, как описано ниже;   -  person Marco    schedule 12.01.2011


Ответы (5)


Будет ли это связано с тем, что исчерпан максимальный объем дискового пространства и в буфере файловых потоков все еще есть данные; fclose'ing файловый поток сбрасывает его (записывает все данные в буфер), операция записи завершится ошибкой, так как достигнуто максимальное место на диске.

Я предлагаю вам ограничить проблему, вызвав fclose() сразу после fopen(). Если все получилось, то что-то не так в коде между fclose() и fopen().

person wengseng    schedule 12.01.2011
comment
Что касается места на диске, то его предостаточно (34 ГБ); Это хороший вариант, я попробую fclose() сразу после fopen(); - person Marco; 12.01.2011
comment
fclose() сразу после того, как fopen() приводит к той же проблеме, ничего плохого в моем промежуточном коде. - person Marco; 12.01.2011
comment
@Marco, тогда, как подсказал мой ответ, программа, генерирующая output.txt, вероятно, не завершена. - person Moo-Juice; 12.01.2011
comment
@Moo-Juice: я думаю, что это закончено, потому что, когда я запускаю программу вручную, без использования моей программы, и позволяю ей работать, как только сгенерирован output.txt, я могу вручную редактировать/удалять ее. Так что это возможно даже ВО ВРЕМЯ работы программы. Это действительно сводится к flcose/fopen - person Marco; 12.01.2011
comment
@Marco: fclose () сразу после fopen () приводит к той же проблеме, что, если вы полностью удалите их? - person Yakov Galka; 12.01.2011
comment
Интересный. Когда я делаю только runProgram(); файл также заблокирован (поэтому я сделал неправильное предположение, что запуск программы вручную приводит к тому же результату, что и runProgram() в моей программе). Я обновлю приведенный выше код, указав, что содержит runProgram(). - person Marco; 12.01.2011
comment
@ybungalobill: Выше я нашел мою функцию runProgram() с выполнением и завершением программы в ней. Это, вероятно, не лучший способ, но я не профессионал. Я попытаюсь выяснить, есть ли у программы «program.exe», которую я использую, способ завершить себя хорошим способом и, таким образом, правильно выпустить output.txt. В этой программе можно реализовать c-код. Кто-нибудь знает, как разрешить программе завершать себя с помощью c-кода? ОС: виндовс хп про. - person Marco; 12.01.2011
comment
@Марко: Это интересно! Вы пытались проверить возвращаемое значение функций fopen() и fclose()? Проверьте их по MSDN... А также измените формат файла (например, output.dat) и режим чтения/записи. Сообщите нам о последних находках... - person wengseng; 13.01.2011

Вероятно, в вашем коде есть другие места, где вы не вызываете fclose, что приводит к утечке файла. Даже в этом коде, если между fopen и fclose (или оператором return, или оператором continue и т. д.) возникает ошибка, вы утечете файл. Пожалуйста, переключитесь на идиому RAII.

Изменить: включите это в свой код:

struct PoorMansFile {
    FILE *_file;
    PoorMansFile(const char* str1, const char* str2) : _file(fopen(str1,str2)) {}
    ~PoorMansFile() { if(_file) fclose(_file); }
    operator FILE*() const { return _file; }
};
int fclose(PoorMansFile& file)
{ 
    if(!file) 
        return 0;

    int t = fclose(file._file);
    file._file = 0; 
    return t; 
}

и заменить каждый

FILE* file = NULL;
file = fopen(str1, str2);

с:

PoorMansFile file(str1, str2);

Расскажите нам, если это поможет;

person Yakov Galka    schedule 12.01.2011
comment
Я проверил свой код, но каждый раз, когда я открываю файл, я также закрываю его. Что вы имеете в виду под идиомой RAAI? - person Marco; 12.01.2011
comment
Я проверил свой код, но каждый раз, когда я открываю файл, я также закрываю его. Это очень наивное заявление. см. RAII или любую хорошую книгу по C++. в основном переключитесь на std::fstream. - person Yakov Galka; 12.01.2011
comment
@Marco, RAII означает Rresource Aquisition Is Iinitialization. По сути, это означает, что если у вас есть объект, у которого есть ресурсы, достаточно построить его, чтобы использовать эти ресурсы. Следовательно, предложение ybungalobill использовать std::fstream. - person Moo-Juice; 12.01.2011
comment
Он компилируется без ошибок, но когда я запускаю скомпилированный исполняемый файл, он выдает следующую ошибку: Debug assertion failed! с указанием пути к fclose.c. Выражение: (поток != NULL). Это как-то связано с объявляемым нами int fclose()? - person Marco; 12.01.2011
comment
@Marco: вы включили перегрузку fclose? - person Yakov Galka; 12.01.2011
comment
@ybungalobill: я не совсем понимаю, что ты имеешь в виду? Как я могу это сделать? - person Marco; 12.01.2011
comment
@Marco: просто вставь это в свой код. Я отредактировал его после первого редактирования, поэтому убедитесь, что это последняя версия. - person Yakov Galka; 12.01.2011
comment
Я вставил его в свой источник, и он успешно компилируется. Программа также работает как обычно, но файл output.txt по-прежнему нельзя редактировать/удалять, пока моя программа работает. Еще большое спасибо за попытку :D - person Marco; 12.01.2011
comment
@Марко: Хорошо. Теперь мы уверены, что вы не сливаете файл. - person Yakov Galka; 12.01.2011
comment
@ybungalobill: Да, мило. Что теперь делать? Что мы действительно знаем, так это то, что fopen() и fclose() вызывают это, потому что только те, которые функционируют без какого-либо кода между ними, уже занимают файл. Смотри посты выше. - person Marco; 12.01.2011
comment
Я сделал эту часть fstream: ifstream file; файл.открыть(файл.txt); файл.закрыть(); и между открытием и закрытием файл нельзя изменить, но после закрытия () он есть. Таким образом, fstream может работать для меня, я только не знаком с ним, поэтому он должен изучить, как читать/записывать файлы с ним. Тем не менее, я хочу знать, почему fopen()/fclose() вызывает у меня проблему. - person Marco; 12.01.2011

Файл все еще может использоваться CRT или ОС — например, ОС может буферизовать запись на диск. fflush() будет очищать только буферы CRT, а не буферы ОС.

person Puppy    schedule 12.01.2011
comment
@Marco: Это будет зависеть от ОС. - person Puppy; 12.01.2011

Просто выстрел в темноте здесь ...

Что внутри runProgram()? Эта функция ждет, пока программа завершится, прежде чем вернуться? Интересно, действительно ли программа, которая записывает данные, все еще работает... отсюда трудно сказать, но я решил выбросить ее туда!

person Moo-Juice    schedule 12.01.2011
comment
внутри runProgram() используется ShellExecute() для запуска программы; эта программа генерирует output.txt, и самый простой способ проверить, может ли программа быть завершена (система (taskkill)) - это проверить, существует ли output.txt (программа не закрывается после генерации, и это нельзя изменить). И вот в чем сейчас проблема. Первый запуск не является output.txt, так что все идет нормально. Но после первого запуска следует удалить файл output.txt, чтобы второй запуск прошел нормально. Но я не могу удалить output.txt, потому что он используется. - person Marco; 12.01.2011
comment
@Марко, то, что файл существует, не означает, что он закрыт или программа завершила работу ... - person Moo-Juice; 12.01.2011
comment
Конечно, файл существует так же, как вы его открываете, поэтому при первом запуске ShellExecute() программы, создающей файл, этот файл будет для вас. Как только вы начинаете его читать, программа записи все еще работает. Вероятно, программа чтения достигает конца файла, когда он все еще используется программой, которую вы вызываете, поэтому вы не можете ее удалить. Попробуйте следующее: а) программа, создающая файл output.txt, открывает файл 'o.txt' и записывает в него. б) когда программа завершится, закройте файл «o.txt» и переименуйте его в «output.txt». c) Теперь у вас не должно возникнуть проблем с удалением программы! - person Mr.Gate; 12.01.2011
comment
Я уже пробовал что-то подобное. В этом случае это не программа, которая генерирует output.txt, которая держит его занятым, это моя собственная программа, вызванная fopen() и fclose(). Смотрите комментарии - person Marco; 12.01.2011

Прочитав все ответы и комментарии, я не мог придумать причину проблемы ОП.

Это многопоточная или реентерабельная процедура?

Что произойдет, если fopen дважды и fclose дважды в одном и том же файле? Это может быть причиной проблемы?

В этой мысли предлагаю еще две проверки.

  • printf все вызовы fopen/fclose
  • после fclose сбрасывает файловую переменную в NULL

f = fopen("", ""); printf("fopen => %p", f);
fclose(f); printf("fclose => %p", f); ф = 0;

Если вам неудобно отлаживать printf, вы можете использовать OutputDebugString.

extern void __stdcall OutputDebugStringA(const char*) (только MS VC)

person 9dan    schedule 12.01.2011