读取大文件,文件大小错误
本文关键字:文件大小 错误 文件 读取 | 更新日期: 2023-09-27 18:17:32
我正在尝试从磁盘读取一个大文件并在加载时报告百分比。问题是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"和"'"字符有关?此外,我还有以下一行:
int bytesLoaded = 0;
如果文件是 1GB 大,我是否必须使用"长"代替?谢谢你的时间!
你的直觉是正确的;报告的大小差异是由于换行符造成的。根据 MSDN 文档StreamReader.ReadLine
:
返回的字符串不包含终止回车符或换行符。
根据创建文件的来源,每个换行符将包含一个或两个字符(最常见的是:Windows上的'r'n
;Linux上'n
(。
也就是说,如果您打算将文件读取为字节序列(不考虑行(,则应使用 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 值的单个字节,从而导致字符计数丢失(以及字节数组处理不正确(。
最后,在文本文件的开头也有可能有一个编码前导码(如Unicode字节顺序标记(,这也会被ReadLine
剥离,导致几个字节的进一步差异。
ReadLine 吞噬的行尾,也可能是因为您的源文件的编码比 ASCII 更详细(也许是 UTF8?(。
int.MaxValue
2147483647,因此如果您的文件为>2GB,则使用 int
for bytesLoaded
时会遇到问题。切换到long
。毕竟,FileInfo.Length
被定义为long
。
ReadLine 方法删除尾随行终止字符。