他是一种数据的流,从源头流到目的地。比如文件的拷贝,输入流从文件中读取到进程,输出流从进程写入文件中。
字节流在JDK1.0的时候就被引入了,用以操作字符集类型为ASCII的数据。为了能够操作Unicode类型的数据,JDK1.1引入了字符流。
我们知道,计算机内部所有的信息最终都是以字节的形式存储的,一个字节有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 码。
举例:
对于单字节字符:0XXXXXXX
对于双字节字符:110XXXXXX | 10XXXXXX
对于三字节字符:1110XXXXX | 10XXXXXX | 10XXXXXX
举例:
对于字节流,可以采用BufferedInputStream或者BufferedOutputStream。
对于字符流,可以采用BufferedReader或者BufferedWriter。
这是在读写文件时用到的两个类,对于小文件他们的额性能表现的还不错,但是对于大文件时,尽量使用BufferedReader或者BufferedWriter。
System是Java.lang包下的一个final类,out是其中的一个PrintStream类型的静态成员变量,println是他的一个方法。
引用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 { // 二选一 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); } } 复制代码