从特定位置读取文本文件直到特定长度

时间:2011-12-22 11:37:24

标签: c# streamreader

由于我收到了一个非常糟糕的数据文件,我必须提出代码从特定起始位置和特定长度的非分隔文本文件中读取以构建可用数据集。文本文件不以任何方式分隔,但是我确实有我需要读取的每个字符串的起始位置和结束位置。我已经提出了这个代码,但是我收到了一个错误并且无法找出原因,因为如果我用0替换395就可以了..

e.g。发票编号起始位置= 395,结束位置= 414,长度= 20

using (StreamReader sr = new StreamReader(@"\\t.txt"))
{                    
    char[] c = null;                   
    while (sr.Peek() >= 0)
    {
        c = new char[20];//Invoice number string
        sr.Read(c, 395, c.Length); //THIS IS GIVING ME AN ERROR                      
        Debug.WriteLine(""+c[0] + c[1] + c[2] + c[3] + c[4]..c[20]);
    }
}

这是我得到的错误:

System.ArgumentException: Offset and length were out of bounds for the array 
                          or count is greater than the number of elements from
                          index to the end of the source collection. at
                          System.IO.StreamReader.Read(Char[] b

6 个答案:

答案 0 :(得分:4)

请注意

Seek()对于OP想要的水平来说太低了。请参阅this answer,而不是逐行解析。

此外,正如Jordan所提到的,Seek()存在字符编码和不同字符大小的问题(例如,对于非ASCII和非ANSI文件,如UTF,这可能不适用于此问题)。谢谢你指出了这一点。


原始答案

Seek()仅适用于流,因此请尝试使用sr.BaseStream.Seek(..),或使用其他类似的流:

using (Stream s = new FileStream(path, FileMode.Open))
{
    s.Seek(offset, SeekOrigin.Begin);
    s.Read(buffer, 0, length);
}

答案 1 :(得分:1)

(基于评论的新答案)

您正在解析发票数据,每个条目都在新行上,并且所需数据在每行的固定偏移量处。 Stream.Seek()对于你想要做的事情来说太低了,因为你需要多次搜索,每行一次。而是使用以下内容:

int offset = 395;
int length = 20;
using (StreamReader sr = new StreamReader(@"\\t.txt"))
{
    while (!sr.EndOfStream)
    {
        string line = sr.ReadLine();
        string myData = line.Substring(offset, length);
    }
}

答案 2 :(得分:0)

以下是我的建议:

using (StreamReader sr = new StreamReader(@"\\t.txt"))
{
    char[] c = new char[20];  // Invoice number string 
    sr.BaseStream.Position = 395;
    sr.Read(c, 0, c.Length); 
}

答案 3 :(得分:0)

解决这个问题很久以前,只想发布建议的解决方案

 using (StreamReader sr = new StreamReader(path2))
        {
          string line;
            while ((line = sr.ReadLine()) != null)
            {             
                dsnonhb.Tables[0].Columns.Add("InvoiceNum"  );
                dsnonhb.Tables[0].Columns.Add("Odo"         );
                dsnonhb.Tables[0].Columns.Add("PumpVal"      );
                dsnonhb.Tables[0].Columns.Add("Quantity"    );


                DataRow myrow;
                myrow = dsnonhb.Tables[0].NewRow();
                myrow["No"] = rowcounter.ToString();
                myrow["InvoiceNum"] = line.Substring(741, 6);
                myrow["Odo"] = line.Substring(499, 6);
                myrow["PumpVal"] = line.Substring(609, 7);
                myrow["Quantity"] = line.Substring(660, 6);

答案 4 :(得分:-1)

395是c数组中开始写入的索引。那里没有395指数,最大值是19。 我会建议这样的事情。

StreamReader r;
...
string allFile = r.ReadToEnd();
int offset = 395;
int length = 20;

然后使用

allFile.Substring(offset, length)

答案 5 :(得分:-1)

我已经在git hub上的AdvancedStreamReader项目中创建了一个名为Helpers的类:

https://github.com/jsmunroe/Helpers/blob/master/Helpers/IO/AdvancedStreamReader.cs

相当强大。它是StreamReader的子类,并保持所有功能不变。有一些注意事项:a)它在构建时重置流的位置; b)在使用读卡器时,您不应该寻找BaseStream; c)如果换行符与环境不同,则需要指定换行符,并且该文件只能使用一种类型。以下是一些单元测试,用于演示如何使用它。

    [TestMethod]
    public void ReadLineWithNewLineOnly()
    {
        // Setup
        var text = $"ƒun ‼Æ¢ with åò☺ encoding!\nƒun ‼Æ¢ with åò☺ encoding!\nƒun ‼Æ¢ with åò☺ encoding!\nHa!";
        var bytes = Encoding.UTF8.GetBytes(text);
        var stream = new MemoryStream(bytes);
        var reader = new AdvancedStreamReader(stream, NewLineType.Nl);
        reader.ReadLine();

        // Execute
        var result = reader.ReadLine();

        // Assert
        Assert.AreEqual("ƒun ‼Æ¢ with åò☺ encoding!", result);
        Assert.AreEqual(54, reader.CharacterPosition);
    }


    [TestMethod]
    public void SeekCharacterWithUtf8()
    {
        // Setup
        var text = $"ƒun ‼Æ¢ with åò☺ encoding!{NL}ƒun ‼Æ¢ with åò☺ encoding!{NL}ƒun ‼Æ¢ with åò☺ encoding!{NL}Ha!";
        var bytes = Encoding.UTF8.GetBytes(text);
        var stream = new MemoryStream(bytes);
        var reader = new AdvancedStreamReader(stream);

        // Pre-condition assert
        Assert.IsTrue(bytes.Length > text.Length); // More bytes than characters in sample text.

        // Execute
        reader.SeekCharacter(84);

        // Assert
        Assert.AreEqual(84, reader.CharacterPosition);
        Assert.AreEqual($"Ha!", reader.ReadToEnd());
    }

我写这个是为了我自己的用途,但我希望它会帮助其他人。