读取大文件,文件大小错误

时间:2013-06-07 09:53:57

标签: c# file

我正在尝试从磁盘读取大文件并在加载时报告百分比。问题是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'代替?谢谢你的时间!

3 个答案:

答案 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 方法会删除尾随行终止字符。