IO流知识

IO流知识

ByteArrayOutputStream 与ByteArrayInputStream流关闭问题(内存流)

ByteArrayOutPutStream和ByteArrayInputStream内部封装了缓冲区(内存流),他们是内存读写流,不同于指向磁盘的流,不涉及底层资源的使用,并且底层用的是byte数组并不是调用了磁盘,这个字节数组是它成员变量,当数组不再使用变成垃圾的时候Java的垃圾回收机制会将它回收,关闭流是为了防止底层资源的泄露(内存),并且他自己的close方法并没有实现,如下所示:

/** 底层创建流
 * Creates a new byte array output stream, with a buffer capacity of
 * the specified size, in bytes.
 *
 * @param   size   the initial size.
 * @exception  IllegalArgumentException if size is negative.
 */
public ByteArrayOutputStream(int size) {
    if (size < 0) {
        throw new IllegalArgumentException("Negative initial size: "
                                           + size);
    }
    buf = new byte[size];
}
/** 底层关闭流
 * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
 * this class can be called after the stream has been closed without
 * generating an <tt>IOException</tt>.
 */
public void close() throws IOException {
}

FileOutputStream与FileInputStream流需要关闭问题

需要关闭的

easyPOI导出Excel报错easyPOI导出Excel报org.apache.poi.ss.usermodel.CellStyle.setAlignment(S)V

版本依赖问题,将版本升级到4.1.3版本即可解决问题

耗时 easyPOI与easyExcel与Apache POI导出Excel耗时比较问题

1万条数据(这里的测试不是从库里导出来测试的填充Excel耗时):

easyPOI:1219ms

easyExcel:2298ms

Apache POI:1001(导出Excel不是从库里导出来的)

jdk泛型反射:6319ms

easyPOI 与easyExcel 与ApachePOI导出Excel特点

easyPOI:默认导出的数据的列值是全部上下居中的,默认列的宽度是10 个单位,不能设置全局自适应列的宽度,只能指定每个列的宽度,并且对数字的导出,对数字的类型没有要求,不损失精度,可以直接导出数值,如果需要对数字转义成中文可以直接使用replace进行转义,也可以自己实现IExcelExportStyler接口指定表格的全局样式,对于Date和String类型的时间可以使用注解进行时间格式指定,功能非常齐全,基本实现了全注解式开发,但对开发者对easyPOI基本属性熟练度要求较高,只是百万级别数据,也是分批次导出的和easyExcel导出原理一样。

easyExcel:1.0方法较少,2.0以后,方法较多,注解支持自定义导出属性值的转换器,2.1.6版本较为稳定,它需要自己指定表格的样式,对值的上下居中及各种属性需要自己设置,支持链式操作,导出方法较为简单,但导出的数值类型有要求,对float和double会损失精度,需要自己写转换器进行转为字符串进行导出,导出的数值类型较为单一,但可以自己实现设置全局表格列的自适应,只需要自定义表格的拦截器即可,快速、简单避免OOM的java处理Excel工具!

Apache POI:实现较为繁琐,对开发者要求较高,实现列自适应,需要每次对每列进行设置,很是繁琐,并且每导出一次表格都要重复写很多代码,很是麻烦,如果使用jdk反射虽然降低代码冗余度,但会降低系统的性能,或者ReflectASM框架反射进行反射提高反射性能,总体来说,Apache POI导出表格性能很差,代码冗余度也很高,非常耗内存严重时会导致内存溢出

总结:总体来说,easyPOI较为简单,并且性能较高,对百万级别的数据也支持,其次是easyExcel,最后是Apache POI。

IO包装流如何关闭

  • 一般情况下是:先打开的后关闭,后打开的先关闭;

  • 另一种情况:看依赖关系,如果流a依赖流b,应该先关闭流a,再关闭流b

  • 例如处理流a依赖节点流b,应该先关闭处理流a,再关闭节点流b

  • 当然完全可以只关闭处理流,不用关闭节点流。处理流关闭的时候,会调用其处理的节点流的关闭方法

  • 如果将节点流关闭以后再关闭处理流,会抛出IO异常

  • 在循环中创建流,在循环内关闭每个流

判断一个流是否被关闭,是没有提供直接的API方法判别的。这里要辟个谣,有人说可以通过判断比如inputStream == null来确认流是否被关闭,这是行不通的。可根据

        try {
            inputStream.read();
        } catch (IOException e) {
            e.printStackTrace();
            log.error("InputStream 流已经被关闭了");
        }

FileOutputstream与ObjectOutputstream嵌套关闭

        FileOutputStream out1 = new FileOutputStream("D:\\SingleTon.txt");
        ObjectOutputStream out2 = new ObjectOutputStream(out1);
        out1.close();//是否需要关闭内层的IO流?
        out2.close();

考虑一下,像这样的嵌套IO流,是否应该从内到外依次关闭呢?

答案是不需要!这些IO类都是JDK自带的,调用了最外层的close方法,其实是一层一层向内调用了最内层的IO类的close方法,这也就是装饰者模式。

当然你肯定想问,为什么我之前自内向外逐层关闭也不会抛出异常?

因为就算你对某个流重复关闭多次,也不会抛出异常

Java如何正确的使用try catch finally关闭文件流的总结

/**
 * 测试正确关闭文件流
 */
private static void testCloseFileStream() {
    final Logger LOG = LoggerFactory.getLogger(Cmshome.class);
    String fileName = "";
    InputStream inputStream = null;//声明个引用,因为这个new对象的时候也是会异常的
    try {
        //这里就会异常,如果文件名不存在的话。
        inputStream = new FileInputStream(fileName);
    } catch (IOException e) {
        //这个主要是把出现的异常给人看见,不然就算异常了,看不到就找不到问题所在。
        LOG.debug("loadProperties IOException:" + e.getMessage());
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close(); // 关闭流
            } catch (IOException e) {
                LOG.debug("inputStream close IOException:" + e.getMessage());
            }
        }
    }
}
//错误的关闭文件的方式的解释:
Properties properties = new Properties();
try {
	//这要是异常,直接就到catch语句,下面的close就不会执行啦,关闭就没用啦
	InputStream wrongWay = new FileInputStream(fileName);
	properties.load(wrongWay);
	wrongWay.close(); // 关闭流
} catch (IOException e) {
	e.printStackTrace();
}
 
//下面是new文件流和关闭文件流的源码,有抛异常动作。
public FileInputStream(String name) throws FileNotFoundException {
    this(name != null ? new File(name) : null);
}
 
//这个是抽象类(abstract class)里面的方法,所以没有具体实现过程。
public void close() throws IOException {}

java - 我应该使用close或closeQuietly来关闭输出流吗?

当我们需要关闭输出流时,我们有两个选择。
安静地关闭意味着没有例外地关闭一条小溪。

try {
	close(out)
} catch(IOException e){
}

关闭

try {
	close(out)
} catch(IOException e) {
 throw a Exception;
}

众所周知,在关闭时,输出流会在文件末尾写入一个或多个字符,如果这些写入错误,文件也无法正确打开,例如zipoutputstream。
如果我使用第一个,我会有一些失败关闭的风险。
如果我使用第二个,它会让我的代码不友好。
有人能给我一些建议吗?
很抱歉把这个问题描述得不清楚。
我是说如何安全地进行IO操作。如果资源的释放失败,它会让调用者知道。
谢谢你的回答。特别感谢“唐·罗比”给了我一个链接,其中包含了“法比安·巴尼”的最佳答案

最佳答案

由于Java 7 IOUtils.closeQuietly已经过时,唯一合理的解决方案是try-with-resources它自动关闭资源。

try (InputStream is = new FileInputStream(file)) {
    ...
}

注意,它还解决了正确打开/关闭多个资源的问题

try (InputStream is = new FileInputStream(infile); OutputStream out = new FileOutputStream(outfile)) {
   ...          
}

它也不能抑制close()可能抛出的ioexception,这正是closeQuietly所做的。

windows 系统导出Excel,文件名不支持冒号时间戳

easyPOI会将冒号时间文件名转为中划线,easyExcel和Apache POI则不会转直接报错

文件名中文乱码问题

//将文件名按如下进行设置,根据系统自动编码实现
String fileName = new String(("李玉杰在" +time +"上传"+"return_order.xls").getBytes("GBK"), StandardCharsets.ISO_8859_1);//涉及到中文问题 根据系统实际编码改变

com.alibaba.excel.exception.ExcelAnalysisException: java.lang.NoClassDefFoundError: org/apache/poi/p

解决方案:

1.检查:查看poi版本是否冲突
2.检查是否缺少依赖版本
3.检查poi的版本要大于等于3.17版本

红框的是必须引入的依赖 其他几个看需求引入 版本最好大于等于3.17 并且统一

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.17</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.17</version>
</dependency>

postman测试文件上传接口方法

headers 里头信息:

Content-Type:multipart/form-data
description:""
enabled:true

body 选择:form-data ,key填写requestparm参数,与接口保持一致

很抱歉,作为文本AI助手,我无法绘制思维导图。但是,我可以为您提供一个简要的java IO流知识点总结。 Java IO流Java中用于处理输入和输出的机制。它提供了一种有效的方式来读取和写入数据,以及与文件、网络和其他设备进行交互。 Java IO流包括字节流和字符流两种类型。字节流以字节为单位进行操作,适用于处理二进制数据。而字符流以字符为单位进行操作,适用于处理文本数据。 常用的字节流包括InputStream和OutputStream类,用于读取和写入字节数据。常用的字符流包括Reader和Writer类,用于读取和写入字符数据。可以通过使用字节流和字符流的组合来实现不同类型数据的读写操作。 在Java IO流中,还有一些特殊的流,如缓冲流、转换流、对象流等。缓冲流提供了缓冲区来提高IO性能。转换流用于处理字符编码和解码。对象流用于对Java对象进行读写操作。 此外,Java IO流还包括一些常用的类和方法,如File类用于处理文件和目录,RandomAccessFile类用于对文件进行随机访问,FileInputStream和FileOutputStream类用于读写文件等。 通过组合和使用不同类型的流和类,您可以实现各种复杂的IO操作,如读写文件、网络通信、序列化对象等。 希望这个简要总结对您有所帮助。如果您有任何更具体的问题,请随时提问。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [万字长文+思维导图帮你梳理 Java IO 流,还学不会你来打我(值得收藏)](https://blog.csdn.net/a1405/article/details/116766237)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凌兮~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值