inputStream.read(data)导致的数据错误

本文详细解析使用Java的HttpURLConnection进行GET请求时遇到的字符溢出问题,通过调整字符串读取方式解决缓冲区残留字符导致的数据错误。

哎,java学的不精各种百度copy代码,结果弄出各种奇葩问题。这不百度了一个HttpURLConnection 模拟http请求的就出问题了:

String message = "";
	try {
		URL url = new URL(uri);
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		connection.setRequestMethod("GET");
		connection.setConnectTimeout(5 * 1000);
		connection.connect();
		InputStream inputStream = connection.getInputStream();
		byte[] data = new byte[1024];
		StringBuffer sb = new StringBuffer();
		int length = 0;
		while ((length = inputStream.read(data)) != -1) {
			String s = new String(data, Charset.forName("utf-8"));
			//Log.debug("Http.get", s);
			sb.append(s);
		}
		message = sb.toString();
		inputStream.close();
		connection.disconnect();
	} catch (Exception e) {
		e.printStackTrace();
	}
	return message;

他本来应该返回一段JSON,但是这段代码结尾总是会多出几个字符。

排除了服务器的问题后,终于发现了问题所在:

	String s = new String(data,Charset.forName("utf-8"));

关键部分就是这行代码,我的缓冲区是1024,但是因为内容比较长,分了两次读完。第一次读取了1024后,第二次只读取了100就读完了。于是这1000覆盖了缓冲区的前1000字节,但是剩下的24还在缓冲区!!!

改成下面这样

	String s = new String(data,0,length, Charset.forName("utf-8"));

 

哎,万恶之源的copy

### Java `InputStream.read` 方法详解 #### 一、基本概念 `InputStream.read()` 是 Java 中用于读取输入流中的数据的方法。该方法返回下一个字节的数据作为整数,范围是从 0 到 255;如果已到达流的末尾,则返回 `-1`[^1]。 ```java int data = inputStream.read(); while(data != -1){ System.out.print((char)data); data = inputStream.read(); } ``` 此代码片段展示了如何逐个字符地读取文件内容并打印出来。当遇到文件结束符时(`data == -1`),循环终止。 #### 二、批量读取方式 除了单次读取一个字节外,还可以通过传递缓冲区来一次性读取多个字节: ```java byte[] buffer = new byte[8 * 1024]; // 创建大小为8KB的缓存数组 int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } ``` 这段程序会持续从输入流中读入最多8K的数据至buffer,并立即将这些数据写入输出流直到整个文件被处理完毕[^3]。 #### 三、注意事项与常见错误修复方案 - **关于 `size<=0` 的情况** 流操作过程中不会出现小于等于零的情况(除特殊标记位),因为一旦检测到EOF(End Of File),即返回值为-1,就会停止进一步的操作。 - **防止资源泄漏** 应确保每次打开的流都能正确关闭,可以采用try-with-resources语句简化这一过程: ```java try (InputStream is = new FileInputStream("example.txt")) { // 执行读取逻辑... } catch (IOException ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); } ``` - **解决重复使用问题** 如果需要多次访问同一个输入源的内容,建议先将其复制到内存中再分发给不同的组件调用。下面是一个实用工具函数实现: ```java private static byte[] cloneInputStream(InputStream input) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { byte[] buffer = new byte[1024]; int len; while ((len = input.read(buffer)) > -1) { baos.write(buffer, 0, len); } return baos.toByteArray(); } } ``` 这种方法能够有效避免因尝试重置位置而导致异常抛出的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值