C#streamreader读取(char []缓冲区,int索引,int count)方法在streamreader对象之后无法从文件读取位置大于buffersize

时间:2016-11-23 16:05:18

标签: c# streamreader

更新

我可以确认下面提到的行为对我不利 做一些我之前没有指定过的事情,就是我用读者charPos属性手动播放,因此问题可以重命名:"如何搞砸你的工作正常Read(buffer,int,int)方法&#34 ;答案是简单地手动设置读取器(SR1)位置在流(FSr)缓冲区外的位置(不要与读取操作缓冲区混淆):

循环之前的

(在原始问题的代码中)

 System.Reflection.FieldInfo charPos_private = typeof(StreamReader).GetField("charPos", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly);

并且在循环内(在原始问题的代码中)

charPos_private.SetValue(SR1, string_index);

文件读取器实际读取到1024,然后当文件流读取下一个1024个字符时它变为0。我试图手动设置位置(因为我弄乱了一些模式)并且我没有注意到它不能进入​​1025.

然后,那就是你如何搞砸简单的东西。 非常感谢所有评论的人!非常感激!我将答案设置为包含如何正确执行该示例的示例,我发布的代码也可以正常工作,如果不是那些我没有提到过的那些行。

原始问题

第一次来到这里,

我自学C#。我试图使用streamreader来读取一个大的UTF-8 Linux LF(以\ n结尾)(一个xml)char(或逐块)并且我在它上面执行一些操作然后通过char(或逐块)将其写入新文件char。我有一个streamreader和streamwriter。

我会用文字解释并在最后添加一些代码:

我发现了streamreader Read() Read(char [] buffer,int index,int count)方法,可以对大文件执行不同的操作。我知道这两个只不过是调用相同方法的两种不同方式(我也尝试过ReadBlock)但情况是:Read()方法自动动态填充StreamReader对象 ByteBuffer (数组),当StreamReader对象位置达到默认 bufferSize 参数(通常为1024或4096)时,方法自动开始缓冲下一个1024或4096 或任何缓冲区大小。

但是Read(char [] buffer,int index,int count)并不自动因此当StreamReader对象Position达到buffersize +1时会引发异常。即在1025位置或4097位置(char)(System.Buffer.InternalBlockCopy上的 System.IndexOutofRangeException(Array src,Int32 srcOffsetBytes,Array dst,Int32 dstOffsetBytes,Int32 byteCount))或者如果我试图窥视()查看下一步(System.IO.StreamReader.Peek()上的 System.IndexOutofRangeException)。我的测试文件是300 MB。

*问题是:我如何获得Read(char [] buffer,int index,int count)来自动重新缓冲ByteBuffer(StreamReader:非公共成员ByteBuffer),以便有效地读取更大的文件比缓冲区大小?或换句话说:我如何用Read(buffer_search,0,x_number_of_chars)实际读取大文件? *

我的意思是我不知道我是否需要通过系统反射手动修改ByteBuffer以及我该怎么做。它应该是自动的;手动重新缓冲对于简单的事情来说就像是太多的工作。

在代码中:(我在这里解释一些代码)

做类似的事情:

char current_char;
using (System.IO.FileStream FSw = new FileStream(sourcePath, FileMode.Create))
{
    using (System.IO.StreamWriter SW1 = new StreamWriter(FSw, System.Text.Encoding.UTF8))
    {
        using (FileStream FSr = new FileStream(destinationPath, FileMode.Open))
        {
            using (StreamReader ofile_temp_chars = new StreamReader(fsr, System.Text.Encoding.UTF8))
            {
                while ((current_char = (char)SR1.Read()) != '\uffff')
                {
                    SW1.Write(current_char);
                }
            }
        }
    }
}

该代码成功且没有问题。读取大文件写入新文件。

但是当我尝试指定要读取的字符数时(我实际上必须读取用户定义的字符数,我只是在这里显示一些代码只读取一个字符来简化)然后我需要使用Read(char [] buffer,int index,int count),如下所示:

char[] buffer_search = new char[1]
using (System.IO.FileStream FSw = new FileStream(fePath, FileMode.Create))
{
    using (System.IO.StreamWriter SW1 = new StreamWriter(FSw, System.Text.Encoding.UTF8))
    {
        using (FileStream FSr = new FileStream(fPath, FileMode.Open))
        {
            using (StreamReader ofile_temp_chars = new StreamReader(fsr, System.Text.Encoding.UTF8))
            {
                while (SR1.Peek() != -1)
                {
                    SR1.Read(buffer_search, 0, 1);
                    SW1.Write(buffer_search[0]);
                }
            }
        }
    }
}

当流读取器对象Position到达并传递buffersize(即1025,4097)等时,该代码将以异常(System.IO.StreamReader.Peek()上的System.IndexOutofRangeException)结束...显然是偷看它在缓冲区上有什么不在文件本身上而不是自动重新缓冲结果在ByteBuffer char []之外偷看。

如果我这样做:

char[] buffer_search = new char[1]
using (System.IO.FileStream FSw = new FileStream(fePath, FileMode.Create))
{
    using (System.IO.StreamWriter SW1 = new StreamWriter(FSw, System.Text.Encoding.UTF8))
    {
        using (FileStream FSr = new FileStream(fPath, FileMode.Open))
        {
            using (StreamReader SR1 = new StreamReader(fsr, System.Text.Encoding.UTF8))
            {
                while (!end_of_file)
                {
                    try { SR1.Read(buffer_search, 0, 1); }
                    catch { end_of_file = true; }
                    SW1.Write(buffer_search[0]);
                }
            }
        }
    }
}

然后我将得到一个只包含1024个字符或缓冲区大小的文件。并且将抛出的异常(catched)将是: System.Buffer.InternalBlockCopy上的 System.IndexOutOfRangeException(Array src,Int32 srcOffsetBytes,Array dst,Int32 dstOffsetBytes,Int32 byteCount)    在System.IO.StreamReader.Read(Char []缓冲区,Int32索引,Int32计数)

因此,在这两种情况下,结果都是相同的,缓冲区没有从文件中获取由Read()和ReadLine()方法自动处理的新数据。

增加缓冲区大小等简单的解决方案不会起作用,因为我的文件数百MB并且我试图提高内存效率......(或者像使用Read()更简单,因为我需要使用Read(buffer,0,x_number_of_chars)。这应该是一件简单的事情,并且花费的时间比预期的要长。

感谢您的帮助,

1 个答案:

答案 0 :(得分:3)

你真的不清楚你在问什么。但是,如果你想从一个流阅读器读取任意数量的字符并将它们写入一个编写器,这可以工作:

int bytesRead;
do
{
    bytesRead = SR1.Read(buffer_search, 0, buffer_search.Length);
    if (bytesRead > 0)
    {
        // TODO: process buffer_search in some way.
        SW1.Write(buffer_search, 0, bytesRead);
    }
} while (bytesRead > 0);

这将在需要时将新字符读入内部流编写器缓冲区。