我正在尝试从磁盘读取大文件并在加载时报告百分比。问题是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;
如果该文件可以说1GB大,我是否必须使用'long'代替?谢谢你的时间!
答案 0 :(得分:5)
你的直觉是正确的;报告大小的差异是由于换行符所致。根据{{3}}上的MSDN文档:
返回的字符串不包含终止回车符或换行符。
根据创建文件的来源,每个StreamReader.ReadLine
将由一个或两个字符组成(最常见的是:Windows上为\r\n
; Linux上仅为\n
。
也就是说,如果您打算将文件作为字节序列读取(不考虑行),则应使用newline方法,这样可以避免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"
}
}
修改:FileStream.Read
提出了关于字符编码的重要观点;您的代码应仅用于ASCII文本文件。如果您的文件是使用不同的编码编写的 - 今天最流行的是UTF-8 - 那么结果可能不正确。
例如,考虑三字节十六进制序列E2-98-BA
。默认情况下使用StreamReader
的{{1}}会将其解码为单个字符UTF8Encoding
。但是,此字符不能用ASCII表示;因此,调用☺
将返回与回退字符{{1}}的ASCII值对应的单字节,从而导致字符数丢失(以及错误处理字节数组)。
最后,还有可能在文本文件的开头加编码spender(例如Unicode字节顺序标记),这也会被Encoding.ASCII.GetBytes("☺")
剥离,导致进一步的差异几个字节。
答案 1 :(得分:1)
这是由ReadLine吞噬的行结尾,也可能是因为你的源文件的编码比ASCII更冗长(也许是UTF8?)。
int.MaxValue
是2147483647,因此如果您的文件大于2GB,则int
使用bytesLoaded
会遇到问题。切换到long
。毕竟,FileInfo.Length
被定义为long
。
答案 2 :(得分:0)
ReadLine 方法会删除尾随行终止字符。