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參數,與接口保持一緻