StreamReader跳过线路

穆罗

活跃的成员
加入
2018年4月30日
消息
26
编程经验
3-5
亲爱的朋友们,

我有这个代码,它的StreamReader有时会读取文件罚款,有时跳过几行,我绝对不知道它为什么这样做。
C#:
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://myfile.txt");
            request.Method = WebRequestMethods.Ftp.DownloadFile;
            request.Credentials = new NetworkCredential("user, "pw");
            FtpWebResponse response = (FtpWebResponse)request.GetResponse();
            Stream responseStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(responseStream);

            while (!reader.EndOfStream)
            {
                MessageBox.Show(reader.ReadLine());
            }
            response.Close();
            reader.Close();
 

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,873
地点
切萨皮克,va.
编程经验
10+
If "myfile.txt"在Unix文件格式中,行标记的末尾与Windows不同。
 

穆罗

活跃的成员
加入
2018年4月30日
消息
26
编程经验
3-5
我应该只使用其他方法并下载文件,然后读取文件吗?因为实际上它非常好。这就是我得到的:
C#:
   using (WebClient webcl = new WebClient())
            {
                webcl.DownloadFileAsync(new Uri("http://file.txt/"), datei);
                webcl.DownloadFileCompleted += Webcl_DownloadFileCompleted;
            }
        }
        }

  private void Webcl_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
           if (e.Error == null)
            {
                foreach (string line in File.ReadLines(datei))
                {
                    ortstrassenTableAdapter.Insert(Ortid, line);
               }
               orteTableAdapter.UpdateStrassendatei(Strassendatei, Ortid);

            }
            else
            {
                MessageBox.Show("Ein Fehler ist aufgetreten!" + Environment.NewLine + e.Error.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
   
        //}
 

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,873
地点
切萨皮克,va.
编程经验
10+
将通过FTP下载的文件的内容与HTTP下载的文件进行比较。 'fc.exe / b ftpdownload.txt httpdownload.txt`报告文件完全相同吗?我猜测他们由于Web服务器代表您的文件处理到安装一致的线路结束而不同。
 

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,873
地点
切萨皮克,va.
编程经验
10+
Aha! UseBinary defaults to true. If you set it to false as part of the FTP download, you should get the correct line endings on Windows:

ftpwebrequest.usebinary.
 

sh

众所周知的成员
加入
2018年9月5日
消息
1,982
编程经验
10+
你的代码不喜欢我。

screenshot_9.jpg.

为什么如果您没有远程将文件从流遥控到磁盘?如果要使用流并读取到内存插槽,请使用WebClient,您可以在Dowloadcepleted事件确认文件完成下载后处理完整文件,就像您在上面所做的那样。然后将其读入内存,提供文件并不高静。
 

sh

众所周知的成员
加入
2018年9月5日
消息
1,982
编程经验
10+
If "myfile.txt"在Unix文件格式中,行标记的末尾与Windows不同。
UNIX上的Perl文件夹中应该有一个小程序来解决这个问题。 @skydiver Windows与Unix线结尾 这一个来自我们在编码恐怖时的伙伴。它涵盖了换行符 这Great Newline Schism

虽然,看起来是阶层的,因此它不能再读取读者。如果OP在尝试捕获中盲目地使用此代码而无需处理错误,则会出现似乎文件正在切断中间。对不起,我今天没有更多的时间玩这个问题。我需要深入研究一些ASP工作项目。
 

约翰

C#论坛主持人
工作人员
加入
2011年4月23日
消息
1,157
地点
挪威
编程经验
10+

sh

众所周知的成员
加入
2018年9月5日
消息
1,982
编程经验
10+
是的,这也是对我发生的 Sheepings. - 重要的是要知道原因。

这将给你一些东西来玩::
C#:
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://127.0.0.1/CFile.txt");
            request.Method = WebRequestMethods.Ftp.DownloadFile;
            request.Credentials = new NetworkCredential("admin", "admin");
            using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
            using (Stream responseStream = response.GetResponseStream())
            {
                var FileName = "SampleFile.txt";
                using (Stream fileStream = File.Create(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), FileName)))
                {
                    responseStream.CopyTo(fileStream);
                }
            }
思考这个。为什么运行时它不会抛出这个例外?注意我改变的东西。

没有更多错误。但我同意,你最好使用webclient方法。
 

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,873
地点
切萨皮克,va.
编程经验
10+
如果你看 源代码 for the WebClient it uses WebRequests anyway. The WebClient just gives a us a much easier interface to think and reason with.

Frankly, I'm confused at to why the underlying network stream would be disposed in the code from post #1. The responseresponseReader are not closed until after the while loop. The responseReader has a reference to the responseStream so the garbage collector shouldn't be trying to dispose of the stream, the response object, nor the reader while the loop is still running. I guess I'll just have to try to setup a repro case and try debugging.
 

sh

众所周知的成员
加入
2018年9月5日
消息
1,982
编程经验
10+
XAMPP有一个FTP服务器,您可以安装Skydiver。您只需要在其后端添加您的用户和组,然后在登录中添加您的用户和组。
 

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,873
地点
切萨皮克,va.
编程经验
10+
好的,使用XAMPP而不是IIS。使用具有40行的7KB文本文件测试。

hmmm ...无例外与控制台应用程序......
C#:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace TestFtp
{
    class Program
    {
        static void Main(string[] args)
        {
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://localhost/x64.txt");
            request.Method = WebRequestMethods.Ftp.DownloadFile;
            request.Credentials = new NetworkCredential("user", "password");
            FtpWebResponse response = (FtpWebResponse)request.GetResponse();
            Stream responseStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(responseStream);

            while (!reader.EndOfStream)
            {
                Console.WriteLine(reader.ReadLine());
            }
            response.Close();
            reader.Close();
        }
    }
}

下次尝试Winforms ...也是也不例外。
C#:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TestFtpWinForms
{
    class TestForm : Form
    {
        public TestForm()
        {
            Text = "Test Form";
            var button = new Button() { Text = "Download", Location = new Point(20, 20) };
            button.Click += (o, e) => Download();
            Controls.Add(button);
        }

        void Download()
        {
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://localhost/x64.txt");
            request.Method = WebRequestMethods.Ftp.DownloadFile;
            request.Credentials = new NetworkCredential("user", "password");
            FtpWebResponse response = (FtpWebResponse)request.GetResponse();
            Stream responseStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(responseStream);

            while (!reader.EndOfStream)
            {
                MessageBox.Show(reader.ReadLine());
            }
            response.Close();
            reader.Close();
        }
    }

    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new TestForm());
        }
    }
}

我尝试运行控制台和Winforms应用程序约7次。没有例外抛出。我需要一个更大的测试文件吗?我还尝试了一个使用Linux线结尾的测试文件,其结果是。
 
Last edited:

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,873
地点
切萨皮克,va.
编程经验
10+
啊哈!我让它重现了这个问题。该文件需要不在空白行上结束。这不会导致例外:
C#:
Test 1
Test 2
Test 3
〜这条线实际上是空白〜 
这"〜这条线实际上是空白〜 "应该是一个空白线条。在线论坛编辑不会让我在那里留下一个空行。


但这将是
C#:
Test 1
Test 2
Test 3

现在是时候做一些调试......
 
Last edited:

sh

众所周知的成员
加入
2018年9月5日
消息
1,982
编程经验
10+
根据Johns Link的说法,文件的结尾无关紧要,它在流读取器解析并由Microsoft Docs排除时似乎是正确的。

我附上了我使用的文件。

我认为正在下载的文件是由完成下载的文件流处置,而读者正在读取,因此会对流抛出异常。但是我想,肯定是上帝微软会允许最终用户管理和处理自己的流。正确的?它在我身上黎明时,该文件可能以某种方式负责错误,但我没有,现在没有足够的时间才能找到它来查明。

所以这很有意思,它会在空线上扔晃动。但还有其他空线,所以为什么不投掷其中一个。为什么是最后一个?如果您有时间更深入研究,我很想知道为什么。我仍然认为别的东西可能会导致它。你有多少次测试它?

顺便说一句,我的文件没有空的最后一行。 ðÿ¤ª
 

附件

  • cfile.txt.
    256 bytes · Views: 43

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,873
地点
切萨皮克,va.
编程经验
10+
Here's the reason for the exception thrown by StreamReader.Endofstream.:
StreamReader.readline() 打电话给自己 readbuffer() 作为其工作的一部分,可以建立一系列文本返回。 readbuffer()调用Stream的read()方法,如下所示:
C#:
        internal virtual int ReadBuffer() {
            charLen = 0;
            charPos = 0;

            if (!_checkPreamble)
                byteLen = 0;
            do {
                if (_checkPreamble) {
                    Contract.Assert(bytePos <= _preamble.Length, "possible bug in _compressPreamble.  Are two threads using this StreamReader at the same time?");
                    int len = stream.Read(byteBuffer, bytePos, byteBuffer.Length - bytePos);
                    Contract.Assert(len >= 0, "Stream.Read returned a negative number!  This is a bug in your stream class.");
            :

在这种情况下,它是流的read()实现 ftpdataStream.read():
C#:
        public override int Read(byte[] buffer, int offset, int size) {
            CheckError();
            int readBytes;
            try {
                readBytes = m_NetworkStream.Read(buffer, offset, size);
            } catch {
                CheckError();
                throw;
            }
            if (readBytes == 0)
            {
                m_IsFullyRead = true;
                Close();
            }
            return readBytes;
        }
注意它如何决定打电话 关闭() 在读取零个字节时自身处置。

之后更新: 哎呀。我忘了提到readline()基本上一直在读取readbuffer(),直到读取行,或者无法读取更多字节。由于行在文件末尾结束,呼叫 readbuffer()在做的末尾 引导FTP数据流类以读取零字节。

StreamReader.Endofstream. 还调用ReadBuffer(),如果读取过量字节,则会返回true。不幸的是,正如我们上面看到的那样,ReadBuffer()最终会调用Stream的read()方法 - Kaboom!
 
Last edited:

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,873
地点
切萨皮克,va.
编程经验
10+
Looks to be a bug in the FtpDataStream class. The regular MemoryStream doesn't suffer from the same problem. Here's the console code from post #15 with an extra step to copy from the FTP data stream over into a memory stream.
C#:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace TestFtp
{
    class Program
    {
        static void Main(string[] args)
        {
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://localhost/x64.txt");
            request.Method = WebRequestMethods.Ftp.DownloadFile;
            request.Credentials = new NetworkCredential("user", "password");
            FtpWebResponse response = (FtpWebResponse)request.GetResponse();
            Stream responseStream = response.GetResponseStream();

            Stream copyStream = new MemoryStream();
            responseStream.CopyTo(copyStream);
            copyStream.Seek(0, SeekOrigin.Begin);

            StreamReader reader = new StreamReader(copyStream);

            while (!reader.EndOfStream)
            {
                Console.WriteLine(reader.ReadLine());
            }
            response.Close();
            reader.Close();
        }
    }
}
 

sh

众所周知的成员
加入
2018年9月5日
消息
1,982
编程经验
10+
我会挖到这个晚上。有一天晚上我有空闲时间。所以毕竟,我的亨希得到了确认,某些东西正在处理,它恰好是来自FTP的流。正确的?

我将在本周重新阅读这一点。做得好
 

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,873
地点
切萨皮克,va.
编程经验
10+
这是一种重现问题的方法,而无需在末尾没有空线的特殊文件:
C#:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace TestFtp
{
    class Program
    {
        static void Main()
        {
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://localhost/x64.txt");
            request.Method = WebRequestMethods.Ftp.DownloadFile;
            request.Credentials = new NetworkCredential("user", "password");
            FtpWebResponse response = (FtpWebResponse)request.GetResponse();
            Stream responseStream = response.GetResponseStream();

            var buffer = new byte[1];

            // Read zero bytes
            responseStream.Read(buffer, 0, 0);

            // Now try to read 1 byte
            responseStream.Read(buffer, 0, 1);
        }
    }
}
 
最佳 底部