为什么 System.IO.StreamReader 无法从我的自定义流中读取?

发布于 2024-08-19 20:24:00 字数 2092 浏览 1 评论 0原文

我正在为我的应用程序中的 API 端点创建自定义流。流需要具有我不想进入的自定义逻辑,但足以说明我不能使用内置流类。

我做了实现只读流(继承自 System.IO.Stream)所需的最低限度,并且我已经验证了 System.IO.BinaryReader 类可以从我的流中读取:

Dim reader As New System.IO.BinaryReader(GenerateStream(business, logic))
Dim enc As New System.Text.ASCIIEncoding
Dim contents As String = enc.GetString(reader.ReadBytes(CType(reader.BaseStream.Length, Int32)))

字符串“contents”包含正确的字符串整个流。

但是,我希望能够允许使用 System.IO.StreamReader 类:

Dim reader As New System.IO.StreamReader(GenerateStream(business, logic), System.Text.Encoding.ASCII)
Dim contents As String = reader.ReadToEnd

但无论出于何种原因,ReadToEnd 始终返回空字符串。

有什么想法吗?

这是流:

Public Overrides ReadOnly Property CanRead() As Boolean
   Get
    Return True
   End Get
  End Property

  Public Overrides ReadOnly Property CanSeek() As Boolean
   Get
    Return False
   End Get
  End Property

  Public Overrides ReadOnly Property CanWrite() As Boolean
   Get
    Return False
   End Get
  End Property

  Public Overrides Sub Flush()
   'this method intentionally left blank'
  End Sub

  Public Overrides ReadOnly Property Length() As Long
   Get
    Return 'some business logic'
   End Get
  End Property

  Public Overrides Property Position() As Long
   Get
    Return bytePosition
   End Get
   Set(ByVal value As Long)
    Throw New System.NotSupportedException
   End Set
  End Property

  Public Overrides Function Read(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer) As Integer
   'I return 0 on an end of stream, otherwise the # of bytes successfully read.'
  End Function

  Public Overrides Function Seek(ByVal offset As Long, ByVal origin As System.IO.SeekOrigin) As Long
   Throw New System.NotSupportedException
  End Function

  Public Overrides Sub SetLength(ByVal value As Long)
   Throw New System.NotSupportedException()
  End Sub

  Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer)
   Throw New System.NotSupportedException()
  End Sub

I'm in the process of creating a custom stream for an API endpoint in my app. The stream needs to have custom logic that I don't want to get into, but suffice to say I can't use a built-in stream class.

I did the minimum necessary to implement a read-only stream (inheriting from System.IO.Stream) and I've verified that the System.IO.BinaryReader class can read from my stream:

Dim reader As New System.IO.BinaryReader(GenerateStream(business, logic))
Dim enc As New System.Text.ASCIIEncoding
Dim contents As String = enc.GetString(reader.ReadBytes(CType(reader.BaseStream.Length, Int32)))

The string "contents" contains the correct string for the entire stream.

However, I would like to be able allow the use of the System.IO.StreamReader class:

Dim reader As New System.IO.StreamReader(GenerateStream(business, logic), System.Text.Encoding.ASCII)
Dim contents As String = reader.ReadToEnd

but for whatever reason the ReadToEnd always returns the empty string.

Any ideas?

Here's the stream:

Public Overrides ReadOnly Property CanRead() As Boolean
   Get
    Return True
   End Get
  End Property

  Public Overrides ReadOnly Property CanSeek() As Boolean
   Get
    Return False
   End Get
  End Property

  Public Overrides ReadOnly Property CanWrite() As Boolean
   Get
    Return False
   End Get
  End Property

  Public Overrides Sub Flush()
   'this method intentionally left blank'
  End Sub

  Public Overrides ReadOnly Property Length() As Long
   Get
    Return 'some business logic'
   End Get
  End Property

  Public Overrides Property Position() As Long
   Get
    Return bytePosition
   End Get
   Set(ByVal value As Long)
    Throw New System.NotSupportedException
   End Set
  End Property

  Public Overrides Function Read(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer) As Integer
   'I return 0 on an end of stream, otherwise the # of bytes successfully read.'
  End Function

  Public Overrides Function Seek(ByVal offset As Long, ByVal origin As System.IO.SeekOrigin) As Long
   Throw New System.NotSupportedException
  End Function

  Public Overrides Sub SetLength(ByVal value As Long)
   Throw New System.NotSupportedException()
  End Sub

  Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer)
   Throw New System.NotSupportedException()
  End Sub

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

∞琼窗梦回ˉ 2024-08-26 20:24:00

仔细查看 StreamReader.ReadToEnd 的描述 显示,引用:

如果初始位置在
流未知或流未知
不支持求,底层
流对象还需要
重新初始化。

它进一步说道:

为避免这种情况的发生而产生
强大的代码,你应该使用阅读
方法并存储读取的字符
在预先分配的缓冲区中。

但是,从底层来看,似乎只有 Stream.Read 被调用,它应该提供您需要的输出。但是,您确实知道 StreamReader 读取字符,它会努力将数据解释为字符串。不确定如果不能的话会发生什么。数据由什么组成?


更新:考虑以下测试代码(抱歉,C#,但使用 一个转换器来获取您的代码),我没有包含抽象类中未实现的方法,以免分散对核心的注意力。正如概念证明一样,这似乎适用于 ASCII 编码,并且无需重新初始化或执行 Seek。

public class AsciiStream : Stream
{
    private string dataStream = "abcdefghijklmnopqrstuvwxyz";
    private long position = 0;

    public override bool CanRead
    {
        get { return true; }
    }

    public override bool CanSeek
    {
        get { return false; }
    }

    public override bool CanWrite
    {
        get { return false; }
    }


    public override long Length
    {
        get { return dataStream.Length; }
    }

    public override long Position
    {
        get
        {
            return position;
        }
        set
        {
            position = value < this.Length ? value : this.Length;
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        long bufferPos = offset;
        long max = this.position + count;
        max = max < this.Length ? max : this.Length;
        for (; this.position < max; this.position++)
        {
            buffer[bufferPos] = Convert.ToByte(this.dataStream[(int) this.position]);
            bufferPos++;
        }

        return (int) bufferPos - offset;
    }
}


// call the code like as follows:
StreamReader sReader = new StreamReader(new AsciiStream(), Encoding.ASCII);
string sToEnd = sReader.ReadToEnd();

要点是:问题必须出在您实际的读取代码中或您没有向我们展示的业务逻辑中。您选择的方法本身应该很有效。您是否尝试过手动实现“从头到尾”?或者使用 BinaryReader,使用 ReadBytes(many)`` 读取末尾内容?

Looking closely at the description of StreamReader.ReadToEnd shows, quote:

If the initial position within the
stream is unknown or the stream does
not support seeking, the underlying
Stream object also needs to be
reinitialized.

It further goes on, saying:

To avoid such a situation and produce
robust code you should use the Read
method and store the read characters
in a pre-allocated buffer.

But, looking under the hood, only Stream.Read is called, it seems, which should provide the output you need. But, you do know that StreamReader reads characters, it tries hard to interpret the data as a string. Not sure what happens if it cannot. What does the data consist of?


Update: Consider the following test code (sorry, C#, but use a converter to get your code), I did not include the non-implemented methods from the abstract class so as to not distract from the core. Just as a proof of concept, this seems to work with ASCII encoding and without the need to re-init or an implementation for Seek.

public class AsciiStream : Stream
{
    private string dataStream = "abcdefghijklmnopqrstuvwxyz";
    private long position = 0;

    public override bool CanRead
    {
        get { return true; }
    }

    public override bool CanSeek
    {
        get { return false; }
    }

    public override bool CanWrite
    {
        get { return false; }
    }


    public override long Length
    {
        get { return dataStream.Length; }
    }

    public override long Position
    {
        get
        {
            return position;
        }
        set
        {
            position = value < this.Length ? value : this.Length;
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        long bufferPos = offset;
        long max = this.position + count;
        max = max < this.Length ? max : this.Length;
        for (; this.position < max; this.position++)
        {
            buffer[bufferPos] = Convert.ToByte(this.dataStream[(int) this.position]);
            bufferPos++;
        }

        return (int) bufferPos - offset;
    }
}


// call the code like as follows:
StreamReader sReader = new StreamReader(new AsciiStream(), Encoding.ASCII);
string sToEnd = sReader.ReadToEnd();

Point being: the problem must lie in your actual Read-code or in the business logic you don't show us. The approach you've chosen, on itself, should simply work. Have you tried implementing, by hand, a "read-to-end"? Or with the BinaryReader, reading past the end with ReadBytes(many)``?

客…行舟 2024-08-26 20:24:00

尝试这样做:

Dim reader As New System.IO.StreamReader(
    GenerateStream(business, logic), 
    System.Text.Encoding.ASCII, 
    False
)
Dim contents As String = reader.ReadToEnd

同时确保您不想使用的所有方法都会抛出 NotImplementedException

Try doing this:

Dim reader As New System.IO.StreamReader(
    GenerateStream(business, logic), 
    System.Text.Encoding.ASCII, 
    False
)
Dim contents As String = reader.ReadToEnd

Also make sure all the methods you don't want used will throw NotImplementedException.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文