2013-06-07 5 views
0

Я пытаюсь прочитать большой файл с диска и сообщить процент, пока он загружается. Проблема заключается в том, что FileInfo.Length сообщает о разном размере, чем моя Encoding.ASCII.GetBytes().чтение большого файла, неправильный размер файла

public void loadList() 
    { 
     string ListPath = InnerConfig.dataDirectory + core.operation[operationID].Operation.Trim() + "/List.txt"; 
     FileInfo f = new FileInfo(ListPath); 

     int bytesLoaded = 0; 

     using (FileStream fs = File.Open(ListPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
     using (BufferedStream bs = new BufferedStream(fs)) 
     using (StreamReader sr = new StreamReader(bs)) 
     { 
      string line; 
      while ((line = sr.ReadLine()) != null) 
      { 
       byte[] array = Encoding.ASCII.GetBytes(line); 
       bytesLoaded += array.Length; 
      } 
     } 

     MessageBox.Show(bytesLoaded + "/" + f.Length); 
    } 

В результате

13357/15251 

Там в 1900 байт 'отсутствует'. Файл содержит список коротких строк. Любые советы, почему он сообщает о разных размерах файлов? он должен что-либо делать с символами '\ r' и '\ n' в файле? Кроме того, у меня есть следующая строка:

int bytesLoaded = 0; 

Если файл позволяет сказать, что 1 ГБ большой, нужно ли вместо этого использовать «длинный»? Спасибо за ваше время!

+0

Использование 'int' или' long' здесь не будет иметь значения, см. [Int32.MaxValue] (http://msdn.microsoft.com/en-us/library/system.int32.maxvalue.aspx) , – Stefan

+1

Добро пожаловать в мир кодировок символов - на разных языках используются разные кодировки, поэтому не все ASCII. –

+0

@Aron, использующий 'ReadToEnd' с ** большим файлом **, не будет хорошей идеей. У вас могут быть проблемы с ограниченной памятью или фрагментация LOH. – polkduran

ответ

5

Ваша интуиция верна; разница в сообщенных размерах обусловлена ​​символами новой строки. В документации MSDN по адресу StreamReader.ReadLine:

Возвращаемая строка не содержит завершающего возврата каретки или строки.

В зависимости от источника, который создал файл, каждый newline будет состоять из одного или двух символов (наиболее часто: \r\n на Windows; просто \n на Linux).

Это означает, что если вы намерены прочитать файл как последовательность байтов (независимо от строк), вы должны использовать метод FileStream.Read, который позволяет избежать накладных расходов на кодировку ASCII (а также возвращает правильный счет в total):

byte[] array = new byte[1024]; // buffer 
int total = 0; 
using (FileStream fs = File.Open(ListPath, FileMode.Open, 
           FileAccess.Read, FileShare.ReadWrite)) 
{ 
    int read; 
    while ((read = fs.Read(array, 0, array.Length)) > 0) 
    { 
     total += read; 
     // process "array" here, up to index "read" 
    } 
} 

Редактировать: spender поднимает важный вопрос о кодировках; ваш код должен использоваться только в текстовых файлах ASCII. Если ваш файл был написан с использованием другой кодировки - самой популярной сегодня является UTF-8, тогда результаты могут быть неверными.

Рассмотрим, например, трехбайтную шестую последовательность E2-98-BA. StreamReader, который использует UTF8Encoding по умолчанию, расшифровал бы это как отдельный символ, . Однако этот символ не может быть представлен в ASCII; таким образом, вызов Encoding.ASCII.GetBytes("☺") возвращает одиночный байт, соответствующий значению ASCII резервного символа ?, что приводит к потере количества символов (а также к неправильной обработке массива байтов).

Наконец, существует также возможность кодировки preamble (например, Unicode знаков порядка байтов) в начале текстового файла, который будет также раздели на ReadLine, что приводит к дальнейшему несоответствие нескольких байтов.

+0

Спасибо! что решило мою проблему! Я должен ждать 8 минут, чтобы принять ваш ответ – user2320462

0

Метод ReadLine удаляет символ окончания задней линии.

1

Это конец строки, который проглатывается ReadLine, а также может быть вызван тем, что ваш исходный файл содержит более подробное кодирование, чем ASCII (возможно, это UTF8?).

int.MaxValue является 2147483647, так что вы собираетесь запустить в проблему с помощью int для bytesLoaded, если ваш файл> 2 Гб. Переключитесь на long. В конце концов, FileInfo.Length определяется как long.

Смежные вопросы