Я открываю файл и помещаю его содержимое в строковый буфер, чтобы провести некоторый лексический анализ для каждого символа. Таким образом, синтаксический анализ завершится быстрее, чем последующее количество вызовов fread (), а поскольку исходный файл всегда будет не больше пары МБ, я могу быть уверен, что все содержимое файла всегда будет читаться.
Однако, похоже, возникают некоторые проблемы с обнаружением, когда больше нет данных для анализа, потому что ftell () часто дает мне целочисленное значение, превышающее фактическое количество символов в файле. Это не было бы проблемой с использованием макроса EOF (-1), если бы конечные символы всегда были -1 ... Но это не всегда так ...
Вот как я открываю файл и читаю его в строковый буфер:
FILE *fp = NULL;
errno_t err = _wfopen_s(&fp, m_sourceFile, L"rb, ccs=UNICODE");
if(fp == NULL || err != 0) return FALSE;
if(fseek(fp, 0, SEEK_END) != 0) {
fclose(fp);
fp = NULL;
return FALSE;
}
LONG fileSize = ftell(fp);
if(fileSize == -1L) {
fclose(fp);
fp = NULL;
return FALSE;
}
rewind(fp);
LPSTR s = new char[fileSize];
RtlZeroMemory(s, sizeof(char) * fileSize);
DWORD dwBytesRead = 0;
if(fread(s, sizeof(char), fileSize, fp) != fileSize) {
fclose(fp);
fp = NULL;
return FALSE;
}
Кажется, что это всегда работает отлично. Далее следует простой цикл, который проверяет содержимое строкового буфера по одному символу за раз, например:
char c = 0;
LONG nPos = 0;
while(c != EOF && nPos <= fileSize)
{
c = s[nPos];
// do something with 'c' here...
nPos++;
}
Конечные байты файла обычно представляют собой последовательность ý (-3) и « (-85) символов, и поэтому EOF никогда не обнаруживается. Вместо этого цикл просто продолжается до тех пор, пока nPos не будет иметь более высокое значение, чем fileSize - что нежелательно для правильного лексического анализа, потому что вы часто пропускаете последний токен в потоке, в конце которого опускается символ новой строки.
Можно ли в базовом наборе латинских символов предположить, что символ EOF - это любой символ с отрицательным значением? Или, может быть, есть лучший способ сделать это?
#EDIT: Я только что попытался реализовать функцию feof () в своем цикле, но все равно, похоже, также обнаруживать EOF.
nPos == fileSize
находится за пределами выделенной вами памяти. - person Jonathan Leffler   schedule 11.03.2013fread()
не будет сообщать о EOF; вы просили прочитать, что было в файле. Если вы попробуетеgetc(fp)
послеfread()
, вы получите EOF, если только файл не увеличился с тех пор, как вы измерили его длину. Поскольку_wfopen_s()
- нестандартная функция, она может влиять на поведениеftell()
и значение, которое он сообщает. Нет; небезопасно предполагать, что любое отрицательное значение char является EOF. Тип plainchar
может быть подписанным или беззнаковым. - person Jonathan Leffler   schedule 11.03.2013new[fileSize]
. Вероятно, это не идиоматический C ++, но это определенно не C. - person Jonathan Leffler   schedule 11.03.2013_wfopen_s()
наfopen()
, и результатftell()
такой же. Однако после изменения соответствующих строк наLPSTR s = new char[fileSize + 1]
,RtlZeroMemory(s, sizeof(char) * fileSize + 1);
(что также должно завершать его нулем, кстати) и добавленияif(nPos == fileSize)
в начало цикла, теперь он выходит чисто. Если вам нужны очки репутации, дайте соответствующий ответ. - person RectangleEquals   schedule 11.03.2013fgetc()
илиfgetwc()
, в зависимости от того, как вы » re обрабатывает сам файл и не имеет отношения к вашему режиму. Но вы открываете файл в двоичном режиме, о котором я, честно говоря, даже не знал, поддерживается в режиме кодированияccs
. Размер буфера должен быть правильным в байтах, если вы использовали вычисленную длину файла + 1 (+1 для терминатора). Если открытие в двоичном режиме и указание подсказки кодирования для запроса анализа спецификации работает, тем лучше. - person WhozCraig   schedule 11.03.2013