他是一種數據的流,從源頭流到目的地。好比文件的拷貝,輸入流從文件中讀取到進程,輸出流從進程寫入文件中。html
字節流在JDK1.0的時候就被引入了,用以操做字符集類型爲ASCII的數據。爲了可以操做Unicode類型的數據,JDK1.1引入了字符流。linux
咱們知道,計算機內部全部的信息最終都是以字節的形式存儲的,一個字節有8位,每一位上都是0或者1。那麼總共有256種組合方式。在上世紀60年代,美國製定了一套英語字符與二進制位之間的關係。這種關係被稱爲ASCII碼,他一共規定了128個字符的編碼,好比空格是32,大寫的A是65。這128個字符只佔用了一個字節的後七位,第一位設置爲0。
可是世界上的語言不止包括128個字符,而且相同的ASCII碼也會被翻譯成不一樣的字符。所以,想打開一個文本文件,就必須知道他的編碼方式。這時候Unicode就出現了,他將世界上全部的符號都歸入其中,每一個符號都給予一個編碼,那麼亂碼的問題就解決了。
可是Unicode也存在問題,那就是只規定了符號的代碼,並無規定二進制代碼如何存儲。好比說某個字符佔兩個字節,那麼計算機怎麼知道他是表明兩個佔一個字節的字符仍是一個佔兩個字節的字符呢?
互聯網的普及,迫切須要一種統一的編碼方式。UTF-8就是Unicode使用最普遍的一種實現,還有UTF-16(用兩個或四個字節表示一個字符),UTF-32(用四個字節表示一個字符)。UTF-8最大的特色就是採用一種變長的編碼方式存儲字符。
UTF-8的編碼規則:
面試
1.對於單字節的符號,字節的第一位設爲0,後面7位爲這個符號的 Unicode 碼。所以對於英語字母,UTF-8 編碼和 ASCII 碼是相同的。緩存
2.對於n字節的符號(n > 1),第一個字節的前n位都設爲1,第n + 1位設爲0,後面字節的前兩位一概設爲10。剩下的沒有說起的二進制位,所有爲這個符號的 Unicode 碼。
bash
舉例:
對於單字節字符:0XXXXXXX
對於雙字節字符:110XXXXXX | 10XXXXXX
對於三字節字符:1110XXXXX | 10XXXXXX | 10XXXXXX
網絡
舉例:app
對於字節流,能夠採用BufferedInputStream或者BufferedOutputStream。
對於字符流,能夠採用BufferedReader或者BufferedWriter。工具
這是在讀寫文件時用到的兩個類,對於小文件他們的性能表現的還不錯,可是對於大文件時,儘可能使用BufferedReader或者BufferedWriter。性能
System是Java.lang包下的一個final類,out是其中的一個PrintStream類型的靜態成員變量,println是他的一個方法。ui
引用Java doc中的描述:
An abstract representation of file and directory pathnames.
-對文件及文件路徑的抽象表明。意思就是File類只表明這個文件的路徑,而不表明文件對象。在Java7引入的nio包中的Path類與io中的File本質上是一個東西。(Path.toFile()=File.toPath(),兩者之間能夠相互轉換)。
NIO被翻譯爲(new IO)或者(Non-blocking IO-非阻塞的IO),在Java7的時候被引入,與IO直接磁盤讀寫不一樣的是,NIO採用緩存的方法對文件進行操做。
\r\n
,在Linux系統中是\n
。代碼以下:
public static void getByteFromWeb() {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("https://www.baidu.com/");
try (CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) {
//注意,我這裏並無設置編碼字符集
InputStream inputStream = httpResponse.getEntity().getContent();
int byteToInt;
while ((byteToInt = inputStream.read()) != -1) {
System.out.print((char) byteToInt);
}
}catch (Exception e){
throw new RuntimeException(e);
}
}
複製代碼
打印結果以下:
InputStreamRead
的構造方法,爲InputStream設置字符集:
InputStreamReader inputStream = new InputStreamReader(httpResponse.getEntity().getContent(),Charsets.UTF_8);
複製代碼
這時候再打印結果就能看到咱們想要的情形:
代碼以下:
public static void getByteFromProcess(){
try {
ProcessBuilder processBuilder = new ProcessBuilder("{commend}");
Process start = processBuilder.start();
InputStreamReader inputStream = new InputStreamReader(start.getInputStream(),Charsets.UTF_8);
int byteToInt;
while ((byteToInt = inputStream.read())!=-1){
System.out.print((char)byteToInt);
}
}catch (Exception e){
throw new RuntimeException(e);
}
}
複製代碼
經過這個發現好玩的事情,在new ProcessBuilder("{commend}")
中寫入:
("cmd.exe", "/C", "start")
複製代碼
能夠經過代碼啓動cmd
,也能夠經過
("C:\\Windows\\System32\\calc.exe")
複製代碼
啓動本機的計算器。
使用commons-io包裏面的FileUtils.writeLines()方法,引入Maven依賴後:
public static void writeLinesToFile1(List<String> lines, File file) {
try {
FileUtils.writeLines(file, lines);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
複製代碼
使用BufferedWriter.write()方法逐行寫入:
public static void writeLinesToFile2(List<String> lines, File file) {
try {
Writer writer = new FileWriter(file);
BufferedWriter bufferedWriter = new BufferedWriter(writer);
for (String s : lines
) {
bufferedWriter.write(s);
bufferedWriter.write("\n");
}
bufferedWriter.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
複製代碼
使用Files工具中的write()方法整個寫入:
public static void writeLinesToFile3(List<String> lines, File file) {
try {
Files.write(file.toPath(), lines);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
複製代碼
使用IOUtils.writeLines()整個寫入:
public static void writeLinesToFiles4(List<String> lines, File file) {
try {
// 須要設置append爲true,將字節寫入文件中
Writer writer = new FileWriter(file, true);
IOUtils.writeLines(lines, null, writer);
// OutputStream outputStream = new FileOutputStream(file);
// IOUtils.writeLines(lines, null, outputStream, Charset.defaultCharset());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
複製代碼
使用InputStream.read()方法逐個讀取:
public static List<String> readFile1(File file) {
List<String> list = new ArrayList<>();
//使用StringBuilder將獲取的單個字符拼接成字符串
StringBuilder stringBuilder = new StringBuilder();
try {
InputStream inputStream = new FileInputStream(file);
int byteToInt;
while ((byteToInt = inputStream.read()) != -1) {
char c = (char) byteToInt;
if (c != '\r' && c != '\n') {
stringBuilder.append((char) byteToInt);
} else {
if (!stringBuilder.toString().equals("")) {
list.add(stringBuilder.toString());
stringBuilder.delete(0, stringBuilder.length());
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return list;
}
複製代碼
使用BufferReader.readLine()方法逐行讀取:
public static List<String> readFile2(File file) {
List<String> list = new ArrayList<>();
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
String s;
while ((s = bufferedReader.readLine()) != null) {
list.add(s);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return list;
}
複製代碼
使用Files工具中的readAllLines()方法整個讀取:
public static List<String> readFile3(File file) {
List<String> list;
try {
list = Files.readAllLines(file.toPath());
} catch (IOException e) {
throw new RuntimeException(e);
}
System.out.println();
return list;
}
複製代碼
使用FileUtils.readFileToString()方法整個文檔讀取:
public static List<String> readFile4(File file){
List<String> list = new ArrayList<>();
try {
list.add(FileUtils.readFileToString(file, Charset.defaultCharset()));
} catch (IOException e) {
throw new RuntimeException(e);
}
return list;
}
複製代碼
使用IOUtils.readLines()方法整個文檔讀取:
public static List<String> readFile5(File file) {
try {
InputStream inputStream = new FileInputStream(file);
return IOUtils.readLines(inputStream, Charset.defaultCharset());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
複製代碼