案例 1-1: InputStream 的用法

本文介绍了一个简单的Java程序示例,演示了如何使用InputStream从指定文件读取内容并将其输出到控制台。该程序利用FileInputStream进行文件读取操作,并通过循环确保所有数据都被正确读取。
/* * 案例 1-1: InputStream 的用法 * 目标: 掌握 InputStream 的用法 * 读取指定文件的内容,并将其原样输出至屏幕上 * 使用方法:java ReadFile [文件名] */ import java.io.*; public class ReadFile { /** * @param args */ public static void main(String[] args) { // 定义一个 byte数组 用于接收从文件中读出的字节 // 注意它的长度为 1024 byte[] buff = new byte[1024];// 1 int n; FileInputStream fis = null; // 生成对象 infile 准备读取文件 try{ fis = new FileInputStream(args[0]);//2 // 从文件读取数据 while((n = fis.read(buff)) != -1)//3 { // 写入System.out System.out.write(buff, 0, n); } }catch(IOException e) { System.out.println(); } // 清理 finally{ try{ // 关闭 FileInputStream 流 fis.close(); }catch(IOException e){ System.out.println("文件错误"); System.exit(1); } } } } /* * 这个类从控制台接收一个参数,用于指定在程序中打开的文件, * 在//2处 使用它来创建一个FileInputStream对象 * 在//3处 通过它的方法read()将文件内容读入到//1处定义的字节数组中,然后使用System.out的一个 * 方法write()将字节数组中的数据输出到控制台.注意这里的字节数组大小为1024,所以,在指定读取的 * 文件时不要指定太大的文件. */
从日志来看,您的离线地图更新在解压第一个包(KVM_Navi_EU_148_1.zip)后,开始处理第二个包(KVM_Navi_EU_148_2.zip)时卡在27.8%进度。以下是详细分析和解决方案: ### 问题根因分析 1. **进度计算逻辑缺陷**: - 当前进度计算公式可能为:`(当前包已处理量/当前包总量) * 单包权重 + 已完成包权重` - 当切换到新包时,`当前包已处理量`被重置为0,但总进度未正确累加已完成包的权重 2. **文件操作阻塞**(关键发现): ```java 2025-08-27 20:56:12.523 拷贝 KVM_Navi_EU_148_2.zip: 10.0MB/3.0GB progress:27.8 ``` - 日志显示从解压切换到拷贝操作时卡住 - 可能原因:文件句柄未释放/存储设备I/O阻塞 3. **多包处理状态机问题**: - 缺少包切换时的状态同步机制 - 新包开始处理时未立即更新全局进度 ### 解决方案 #### 1. 修改进度计算逻辑 ```java // 新进度计算公式示例 float calculateProgress(int currentPkgIndex, long currentPkgProcessed, long currentPkgTotal) { // 基础进度:已完成包的固定权重(如每个包占30%) float baseProgress = currentPkgIndex * 30.0f; // 当前包进度(占总进度的30%) float currentPkgRatio = (float)currentPkgProcessed / currentPkgTotal; float currentPkgProgress = currentPkgRatio * 30.0f; // 总进度 = 基础 + 当前包 return baseProgress + currentPkgProgress; } ``` #### 2. 添加包切换事件处理 ```java // 在包切换时强制更新进度 void onPackageSwitched(int newPkgIndex) { // 立即更新为已完成包的固定进度 float minProgress = newPkgIndex * 30.0f; // 假设每个包占30% notifyProgress(minProgress); // 释放前一个包的资源 System.gc(); try { Thread.sleep(100); // 给GC时间 } catch (InterruptedException ignored) {} } ``` #### 3. 增强文件操作健壮性 ```java // 使用NIO非阻塞拷贝 void copyFileWithNIO(File src, File dst) throws IOException { try (FileChannel in = new FileInputStream(src).getChannel(); FileChannel out = new FileOutputStream(dst).getChannel()) { long transferred = 0; long size = in.size(); while (transferred < size) { transferred += in.transferTo(transferred, size - transferred, out); updateProgress(transferred, size); // 实时更新进度 } } } ``` ### 关键修改点 1. **进度计算优化**: - 旧算法:`当前包进度 * 总权重` → 导致包切换时进度回退 - 新算法:`已完成包固定进度 + 当前包进度` → 保证进度单调递增 2. **I/O阻塞处理**: ```mermaid graph TD A[开始处理新包] --> B{是否卡住?} B -->|是| C[强制GC] C --> D[等待100ms] D --> E[重试操作] B -->|否| F[正常流程] ``` 3. **日志增强建议**: ```java Log.d(TAG, String.format("包切换: %d->%d 释放资源...", oldIndex, newIndex)); Log.d(TAG, "JVM内存状态: " + Runtime.getRuntime().freeMemory()/1024 + "KB free"); ``` ### 验证方法 1. **模拟测试**: ```java // 测试包切换时的进度 void testProgress() { // 模拟3个包,每个3GB assert calculateProgress(0, 1_500_000_000L, 3_000_000_000L) == 15.0f; // 第一个包50%*30% assert calculateProgress(1, 0L, 3_000_000_000L) == 30.0f; // 第二个包开始 } ``` 2. **性能监控**: ```bash # 监控存储I/O adb shell dumpsys diskstats ``` ### 典型修复案例 某类似问题最终发现: 1. ZIP解压库在关闭文件时没有真正释放句柄 2. 解决方案: ```java // 在解压完成后强制关闭流 for (Field f : zipFile.getClass().getDeclaredFields()) { if (f.getType() == InputStream.class) { f.setAccessible(true); ((InputStream)f.get(zipFile)).close(); } } ``` 建议在您的代码中添加类似的资源释放检查。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值