你碰到过StreamReader.Peek的异常情况

简介:

工作中有个需求需要采集每个服每天用户的登录信息、道具使用情况等(用来做数据分析),这些信息、数据

是通过技术那边的Http接口来获取,为了提高效率,节省流量,没有用XML或JSON格式的输出(数据量比较

大,用XML格式或JSON格式或增加许多冗余的信息,优劣暂且不讨论),而是用简单的文本形式,Http接口

数据的输出的格式如下:

 

1:不同记录以"\r\n"分隔

2:不同字段以“|||”分隔

 举个例子(假设),用户每天的登录信息:

字段排列顺序为: GameID|||UserID|||UserName|||ServerID|||ServerName|||IP|||RegistedFrom

|||FromSiteUrl|||LoginTimes|||CreateDate

下面是其中一个函数,大家如果不想看,完全可以先跳过,只是为了说明下面的问题

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
public bool ParseDataFromUrl( string url, string serverName, string dateTime)
{
 
     HttpWebResponse httpResponse = RequestUtil.GetHttpResponse(url);
 
 
     if (httpResponse == null )
     {
         log.Error(url + ": 解析URL内容出错,请检查配置表" );
 
         SendMessage.MessageSending(serverName + ": 解析URL内容出错,请检查配置表" );
 
         return false ;
     }
 
     StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream(), Encoding.GetEncoding( "UTF-8" ));
 
     string [] columns = { "ID" , "GameID" , "UserID" , "UserName" , "ServerID" , "ServerName" , "IP" ,
             "RegistedFrom" , "FromSiteUrl" , "LoginTimes" , "CreateDate" , "GatherDate" };
 
     Type[] dataTypes = {                                
                            typeof (Int32),  typeof (Int32),  typeof ( string ),
                              typeof ( string ), typeof ( string ), typeof ( string ),                                
                              typeof ( string ), typeof ( string ), typeof ( string ),
                              typeof (Int32),  typeof (Int32),  typeof ( string )                           
                        };
     DataTable dtDataSource = DataTableUtil.DataTableStruct(columns, dataTypes);
 
     try
     {
         string line = "" ;
         string tableName = ConfigurationSettings.AppSettings[ "UserLoginInfoTable" ].ToString().Trim();
 
         //while ((line = streamReader.ReadLine()) != null)      
         while (streamReader.Peek() >= 0)
         {
             line = streamReader.ReadLine();
             if (line == "<?php exit;?>" || line == "" )
                 continue ;
 
             if (!line.Contains( "|||" ))
             {
                 log.Fatal( "ParseDataFromUrl: " + serverName + url + "----没有权限获取日志内容 " );
 
                 SendMessage.MessageSending(serverName + "无权限访问日志内容,请检查配置表" );
                 continue ;
 
             }
 
             string [] logText = line.Split( new string [] { "|||" }, StringSplitOptions.None);
 
             DataRow row = dtDataSource.NewRow();
 
             row[ "ID" ] = 0;
 
             if (RegexUtil.IsNumeric(logText[2]))
             {
                 row[ "GameID" ] = Int32.Parse(logText[2]);
             }
             else
             {
                 row[ "GameID" ] = 0;
             }
             row[ "ServerID" ] = logText[3].Trim();
             row[ "ServerName" ] = serverName;
             row[ "IP" ] = logText[7].Trim();
             row[ "UserID" ] = logText[0].Trim();
 
             row[ "UserName" ] = logText[1].Trim();
             row[ "RegistedFrom" ] = logText[5].Trim();
             row[ "FromSiteUrl" ] = logText[4].Trim();
 
             if (RegexUtil.IsNumeric(logText[8].Trim()))
             {
                 row[ "LoginTimes" ] = Int32.Parse(logText[8]);
             }
             else
             {
                 row[ "LoginTimes" ] = 0;
             }
 
             if (RegexUtil.IsNumeric(logText[9]))
             {
                 row[ "CreateDate" ] = Int32.Parse(logText[9]);
             }
             else
             {
                 row[ "CreateDate" ] = 0;
             }
             row[ "GatherDate" ] = dateTime;
             dtDataSource.Rows.Add(row);
 
             if (dtDataSource.Rows.Count == 5000)
             {
                 ImportToDataBase(dtDataSource, tableName);
                 dtDataSource.Rows.Clear();
             }
         }
 
         httpResponse.Close();
         streamReader.Close();
 
 
         if (dtDataSource.Rows.Count > 0 && dtDataSource.Rows.Count < 5000)
         {
             ImportToDataBase(dtDataSource, tableName);
         }
 
     }
     catch (Exception exc)
     {
 
         log.Fatal( "函数ParseDataFromUrl出错:" + exc.Message);
 
         SendMessage.MessageSending( "函数ParseDataFromUrl出错, 详情请见日志!" );
 
     }
 
     return true ;
 
}
 
 
 
public static HttpWebResponse GetHttpResponse( string url)
{
     try
     {
         HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
 
         httpRequest.Timeout = 6000000; //1000 * 60 * 10; 用后面的效率低下,会有多余的计算步骤
 
         httpRequest.ContentType = "application/x-www-form-urlencoded" ;
         httpRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; ccdotnet ;.NET CLR 1.1.4322; .NET CLR 2.0.50727)" ;
         httpRequest.Accept = "*/*" ;
         httpRequest.KeepAlive = true ;
         httpRequest.Headers.Add( "Accept-Language" , "zh-cn, en-us; q=0.5" );
         httpRequest.AllowAutoRedirect = true ;
 
         HttpWebResponse response = (HttpWebResponse)httpRequest.GetResponse();
         return response;
     }
     catch (Exception exc)
     {
         return null ;
     }
 
 
}

 

 

 

在测试过程中,遇到了一个让我比较郁闷的问题:采集下来的数据跟接口提供的数据条数不一致,调

试过程居然发现每次运行取得的数据居然都不一致,刚开始还以为是HttpWebResponse 

httpResponse = RequestUtil.GetHttpResponse(url);里面HttpWebRequest对象的Timeout

设置过短的超时引起的数据异常,等到把这个Timeout设置很长后,定位错误情况的时候,居然发现

罪魁祸首是:while (streamReader.Peek() >= 0),往往还没有获取所有记录,Peek就返回了-1

, 查了下MSDN,关于Peek的结束如下:

 

 

Peek 方法返回一个整数值以便确定是否到达文件末尾,或发生其他错误。这样一来,用户在将返回值

强制转换为 Char 类型之前就可以首先检查该值是否为 -1。换句话说,它不需要先转换字符,即可返

回是否达到文件末尾。

http://msdn.microsoft.com/zh-cn/library/system.io.streamreader.peek.aspx


现在情况是StreamReader对象还没读写到文件末尾,那肯定是发生了其它错误,但是又没有什么异

常抛出,我只好改用while ((line = streamReader.ReadLine()) != null)来读写,测试结果完全

正确,于是网上搜索了下,发现邀月的博客的博客里面有涉及这方面的内容

http://www.cnblogs.com/downmoon/archive/2010/08/18/1802095.html

不过他里面所涉及的是StringReader.ReadLine出现的异常的情况(具体情况大家可以去他博客

看看):

StringReader.ReadLine 方法将行定义为后面跟有下列符号的字符序列:换行符(“\n”)、回车符

(“\r”)或后跟换行符的回车符(“\r\n”)。 所产生的字符串不包含终止回车符和/或换行符 如果

到达基础字符串的结尾,则返回值为 null  我的理解:如果由于编码的问题,导致读取异常,也

就是无法读取行标志时,可能会认为已到文件结尾而断下行的读取。这也解释了为什么会有时读取

不完整的原因。

搜索了很久发现了有一些网友也碰到了类似的问题,不过也没发现有价值的解释,我列举下搜索到的

一些资料

http://www.netframeworkdev.com/net-framework-networking-communication

/streamreader--peek-null-61609.shtml

http://bbs.bccn.net/viewthread.php?tid=88673 

http://www.pcreview.co.uk/forums/thread-1333549.php

http://www.go4answers.com/Example/streamreaderpeek-blocks-theres-no-172470.aspx

这些人碰到的问题大体跟我一样,不过都没啥合理的原理解释,除了MSDN上面那简短的解释,不知哪位

大佬曾经碰到过这问题!

出处:http://www.cnblogs.com/kerrycode/

相关文章
接口返回aop.unknow-error,系统繁忙
创建门店返回aop.unknow-error,大多数是因为传入的门店详细地址、店铺经纬度、省市区号指向的不是同一个地点而造成的,出现此类问题时,ISV需要首先核对上述地址是否指向相同地方,经纬度是否填反,是否没有使用高德坐标系,省市区号是否不是国标,是否填错。
1127 0
|
7月前
Stream流操作-简单结果终止方法
Stream流操作-简单结果终止方法
65 0
|
4月前
you might not need peek
you might not need peek
17 0
|
7月前
Stream方法使用-peek和foreach方法讲解
Stream方法使用-peek和foreach方法讲解
83 0
|
11月前
一个关于List的IndexOutOfBoundsException异常记录
一个关于List的IndexOutOfBoundsException异常记录
70 0
还在stream中使用peek?不要被这些陷阱绊住了
自从JDK中引入了stream之后,仿佛一切都变得很简单,根据stream提供的各种方法,如map,peek,flatmap等等,让我们的编程变得更美好。 事实上,我也经常在项目中看到有些小伙伴会经常使用peek来进行一些业务逻辑处理。 那么既然JDK文档中说peek方法主要是在调试的情况下使用,那么peek一定存在着某些不为人知的缺点。一起来看看吧。
|
Java Apache Spring
isEmpty函数的调用
StringUtils中isEmpty函数的使用
109 0
isEmpty函数的调用
|
前端开发 Java 程序员
工作 3 年不懂 isEmpty 和 isBlank 的区别,被00后上了一课
工作 3 年不懂 isEmpty 和 isBlank 的区别,被00后上了一课
101 0
工作 3 年不懂 isEmpty 和 isBlank 的区别,被00后上了一课
有关StringUtils中isEmpty和 isBlank 的使用场景
有关StringUtils中isEmpty和 isBlank 的使用场景
77 0
|
前端开发 Apache
isEmpty 和 isBlank 的用法区别,你都知道吗?
isEmpty 和 isBlank 的用法区别,你都知道吗?
172 0
isEmpty 和 isBlank 的用法区别,你都知道吗?