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参数,与接口保持一致