一小段代碼的實現(xiàn)筆記

最近有一項工作,保存 Excel 格式的電子表格至 postgresql 的數(shù)據(jù)表,要求使用 Java 編寫一段代碼把這事辦了。

如果 Java 不是問題,那么關(guān)于這事的一個簡單想法是:首先,Excel 格式有點復(fù)雜了,改成 CSV 格式。之后,第一步就是打開CSV文件;第二步讀取指定列;第三步寫數(shù)據(jù)庫。

但 java 真的是個問題,無他只因不會。關(guān)于 Java ,有個網(wǎng)站 Java Tutorials Learning Paths 內(nèi)容很好,只是有點老 Java 8 版本。另外 Head First 系列有 Java 版,這個更老 Java 5. 這本我有,可以留言。

我看 Java 的主要特性,如虛擬機、一次編譯到處運行什么的都無所謂。重點是 Java 是基于類的面向?qū)ο笳Z言,這點與 C++ 類似,與 Js 不同。但是 Java 比 C++ 徹底,或者說更純粹,濃郁的90年代現(xiàn)代化的感覺。

Unix 一切皆文件,Windows 一切皆視窗,Java 一切皆對象。

對象 Object 是什么?

==對象是類的實例或數(shù)組。== 但要注意的是 Java 中,所有類的基類名為 class Object,即 java.lang.Object ,此對象非彼對象。

好,知道了什么是對象,約等于我們學(xué)會了 Java,接下來的問題就簡單了。

怎么打開 CSV 文件?

JDK 中沒有原生庫支持 CSV 操作。習(xí)慣 Python 的,可能有點不爽了。但這也不是什么大事,Apache Commons CSV 庫也很標(biāo)準(zhǔn)。

下面是一個解析 Excel CSV File 文件的例子:

Reader in = new FileReader("path/to/file.csv");
Iterable<CSVRecord> records = CSVFormat.EXCEL.parse(in);
for (CSVRecord record : records) {
    String lastName = record.get("Last Name");
    String firstName = record.get("First Name");
}

這個例子很簡單,對于只學(xué)習(xí)了 5 分鐘 Java 的人,也能看懂。

但我還是想問一下 FileReader 類到底是什么?

FileReader 類是為了方便讀取字符文件而存在的。這種便利來自于構(gòu)造器假設(shè)了字符編碼與字節(jié)緩沖器的尺寸。若要自定義這些參數(shù),需在 FileInputStream 上構(gòu)造 InputStreamReader 。是不是很神奇?剛才還是完全理解的,現(xiàn)在又好像什么都不懂了。

這需要先了解一下 Java 是怎么處理 IO 的。這里,Java 引入了 I/O Stream 這一概念,用來抽象描述 IO 操作。所以,流可以表示不同的源與目的,包括磁盤上的文件,設(shè)備,其它程序,內(nèi)存數(shù)組等,同時支持多種數(shù)據(jù)類型。這有點 Unix 中文件的意思。流的本質(zhì)是數(shù)據(jù)序列。關(guān)于數(shù)據(jù)序列是如何而來這樣的細節(jié)對于消費者是不應(yīng)該去關(guān)心的。

字節(jié)流是最基礎(chǔ)的一類流。程序使用字節(jié)流完成 8-比特字節(jié)的輸入與輸出。所有字節(jié)流類始于 InputStream 與 OutputStream,它們同為抽象類。

這里又有了新問題,什么是抽象類?

Abstract Methods and Classes

抽象類是被 abstract 修飾聲明的類。

  1. 抽象類可以不包含抽象方法。
  2. 包含抽象方法的類必為抽象類。
  3. 抽象類可繼承不可實例。

當(dāng)一個抽象類被繼承時,其子類通常提供父類所有抽象方法的實現(xiàn)。若不如此,子類也需用 abstract 修飾聲明。

接口中的方法,若匪經(jīng) default 或 static 修飾聲明,則意為抽象,因此 abstract 未見于接口方法。

雖然 Python 中所有類的基類也名為 class Object ,但它確實沒有抽象類,也沒有接口。而 python 的 metaclasses java 似乎也沒有。也許應(yīng)該用 C++ 或 C# 來類比??墒钦l又會那些呢。

參見 python java 類定義對比。

一段字節(jié)流的示例代碼:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyBytes {
    public static void main (String[] args) throws IOException {
        
        FileInputStream in = null;
        FileOutputStream out = null;
        
        try {
            in = new FileInputStream("xanadu.txt");
            out = new FileOutputStream("outagain.txt");
            int c;
            
            while ((c = in.read()) != -1) {
                out.write(c);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
}

這個例子很簡單,對于只學(xué)習(xí)了 5 分鐘 Java 的人,真的能看懂。

這段示例中,花費最多時間的部分目的在于一次一字節(jié)的讀取輸入流寫入輸出流。

這段示例中,花費最多代碼的部分目的在于幫助避免嚴(yán)重的資源泄漏,因為當(dāng)不在需要時正確的關(guān)閉流是非常重要的。

這段代碼看起來像是一個正常的程序,但它實際代表著一種低階 I/O ,這是應(yīng)該避免的。因為 xanadu.txt 文件包含的是字符數(shù)據(jù),因此最好的方法是使用字符流 character streams ,這是一種為更復(fù)雜的數(shù)據(jù)類型而準(zhǔn)備的流。字節(jié)流僅應(yīng)用于最基礎(chǔ)的 I/O 。

既然如此,為何還要講 byte streams ?因為,其它的所有流類型都構(gòu)建在字節(jié)流之上。

所有字符流類始于 Reader 與 Writer,它們同為抽象類。這兩個名字挺有意思,是因為對于人類來說,字符與字節(jié)相比有了意義,才稱為讀者與作者嗎?

一段字符流的示例代碼:

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyCharacters {
    public static void main(String[] args) throws IOException {
        
        FileReader inputStream = null;
        FileWriter outputStream = null;
        
        try {
            inputStream = new FileReader("xanadu.txt");
            outputStream = new FileWriter("characteroutput.txt");
            
            int c;
            while ((c = inputStream.read()) != -1) {
                outputStream.write(c);
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }
}

這個例子很簡單,對于只學(xué)習(xí)了 5 分鐘 Java 的人,真的能看懂。

有沒有既視感? Character Streams 與 Byte Streams 的示例代碼相似度很高。找茬是個有意思的游戲。

字符流使用字節(jié)流完成物理 I/O ,字符流處理字符與字節(jié)之間的轉(zhuǎn)換。

前文提到的 InputStreamReader 與 OutputStreamWriter 是兩個通用目的 byte-to-character 的橋接流。也是 FileReader 與 FileReader 的父類。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • (一)Java部分 1、列舉出JAVA中6個比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨云閱讀 7,265評論 0 62
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,697評論 18 399
  • 儀征,宋代時叫“儀真郡”,俗稱“真州”,現(xiàn)代儀征的市中心依然叫真州鎮(zhèn),上了年紀(jì)的儀征人都喜歡管“儀征”叫“真州”。...
    禾月heyue閱讀 626評論 0 0
  • 一、養(yǎng)子須教子 1、須知孺子可教,勿謂童子何知。(《增廣賢文》)2、養(yǎng)不教,父之過。(《三字經(jīng)》)3、養(yǎng)子不教如養(yǎng)...
    叫我大表弟吧閱讀 451評論 0 0

友情鏈接更多精彩內(nèi)容