Juan基础28(文件操作和IO流)

编程的本质是用于处理数据——

将数据保留在文件等其他物理设备上,保证数据可以永久保存

File

既可以代表文件,也可以代表目录

可以创建、删除、重命名,但不能读取文件的内容

绝对路径:以根路径(盘符)开头的路径叫绝对路径

相对路径:不是绝对路径的路径(

基本用法

  • 创建对象
  • 调用方法(自己查文档(

举个栗子

  1. import java.io.File;
  2. public class Demo1 {
  3. public static void main(String[] args) throws Exception {
  4. File f=new File(".");//将目录包装File
  5. File f1=new File("src");//将文件包装File
  6. File f2=new File("E:/","Java");
  7. System.out.println(f.exists());
  8. System.out.println(f1.exists());
  9. System.out.println(f2.exists());
  10. System.out.println(f.getAbsolutePath());
  11. System.out.println(f.getCanonicalPath());
  12. File[] files=File.listRoots();
  13. for(File ff:files){
  14. System.out.println(ff);
  15. }
  16. String[] flist=f.list();
  17. for(String flist1:flist){
  18. System.out.println(flist1);
  19. }
  20. }
  21. }
  22. /*
  23. true
  24. true
  25. true
  26. E:\Java\UsingFilesAndIO\.
  27. E:\Java\UsingFilesAndIO
  28. C:\
  29. D:\
  30. E:\
  31. F:\
  32. .idea
  33. out
  34. src
  35. UsingFilesAndIO.iml
  36. */

递归方法遍历文件

  1. import java.io.File;
  2. import java.nio.file.Files;
  3. public class See {
  4. public static void main(String[] args) {
  5. File start=new File("E:/C# C++");
  6. access(start);
  7. }
  8. public static void access(File start) {
  9. File[] subfiles=start.listFiles();
  10. for(File sub:subfiles){
  11. if (sub.isFile()){
  12. System.out.println("正在进入"+sub);
  13. }
  14. else if(sub.isDirectory()){
  15. System.out.println("进入"+sub+"目录");
  16. access(sub);
  17. }
  18. }
  19. }
  20. }

IO流

可以读取文件的内容

可以inputoutput各种物理结点的数据

流的分类

  • 按方向
    • 输入流——读取数据
    • 输出流——写出数据

分辨二者,要从运行程序所在的内存来看:

  • 如果数据是从程序自身流出,用输出流
  • 如果我们的数据是流入程序自身,用输入流
    • 按数据单元
  • 字节流——每个水滴就是一个字节,每次读或者写一个字节,每个Byte是计算机管理数据的最小单元
    因此字节流可以读写任意文件
  • 字符流——每个水滴就是一个字符,每次读或者写一个字符
    可以非常方便的读写文本文件

分辨方式:

  • 字节流以Stream结尾
  • 字符流以ReadWrite结尾

我们可以把输入和输出流比作一个水管,每一个单位看做水管里的一滴水fromat

  • 按照角色来分类
    • 节点流:代表数据源的IO结点
    • 处理流(过滤流、包装流):建立在其他流的基础之上,用于对其他的流进行包装

IO流的基本方法

  • 输入流的基本方法:
    • read():每次读取一滴水
    • int read(xxx[] buff):读取N滴水到数组中,返回实际读取的水滴数
    • int read(xxx[] cbuf,int off,int len)读取数组中间的一段
  • 输出流的基本方法
    • write(int)输出一滴水
    • void write(xxx[] buff)读取N滴水到数组中,返回实际的水滴数
    • void write(xxx[] cbuf,int off,int len)读取数组中间的一段

节点流

字节输入流 字节输出流 字符输入流 字符输出流
抽象基类 InputStream OutputStream Reader Writer
文件 **FileInputStream** **FileOutputStream** **FileReader** **FileWriter**
数组 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter
字符串 StringInputStream StringOutputStream StringReader StringWriter

输入流举例

  1. import javax.imageio.IIOException;
  2. import java.io.FileInputStream;
  3. import java.io.FileNotFoundException;
  4. public class FileInputStreamTest {
  5. public static void main(String[] args) throws Exception {
  6. FileInputStream fis=new FileInputStream("E:\\Study\\Java\\UsingFilesAndIO\\src\\FileInputStreamTest.java");
  7. System.out.println(fis.read());
  8. System.out.println(fis.read());
  9. System.out.println(fis.read());
  10. System.out.println(fis.read());
  11. System.out.println(fis.read());
  12. System.out.println(fis.read());
  13. System.out.println(fis.read());
  14. System.out.println(fis.read());
  15. fis.close();
  16. }
  17. }
  18. /*
  19. 13
  20. 10
  21. 105
  22. 109
  23. 112
  24. 111
  25. 114
  26. 116
  27. */

此处在第一行故意加了一个空行,目的是输出显示回车和换行\n\r对应的数值就是13和10

打印程序本身的案例

  1. import javax.imageio.IIOException;
  2. import java.io.FileInputStream;
  3. import java.io.FileNotFoundException;
  4. public class FileInputStreamTest {
  5. public static void main(String[] args) throws Exception {
  6. FileInputStream fis=new FileInputStream("E:\\Study\\Java\\UsingFilesAndIO\\src\\FileInputStreamTest.java");
  7. byte[] buff=new byte[512];
  8. //创建变量及时记录已被读取的字节数量
  9. int hasRead =0;
  10. //只要读取的量仍然大于0(仍然在读取非空字节),就继续循环
  11. while ((hasRead= fis.read(buff))>0) {
  12. //将读取的字节转化为字符串
  13. String a = new String(buff, 0, hasRead);
  14. System.out.println(a);
  15. //读取几个字节,就恢复几个字节
  16. }
  17. //记得关掉文件
  18. fis.close();
  19. }
  20. }

字节流换汤不换药

  1. import javax.imageio.IIOException;
  2. import java.io.FileInputStream;
  3. import java.io.FileNotFoundException;
  4. import java.io.FileReader;
  5. public class FileReaderTest {
  6. public static void main(String[] args) throws Exception {
  7. FileReader fis=new FileReader("E:\\Study\\Java\\UsingFilesAndIO\\src\\FileInputStreamTest.java");
  8. System.out.println(fis.read());
  9. System.out.println(fis.read());
  10. System.out.println(fis.read());
  11. System.out.println(fis.read());
  12. int hr=0;
  13. char[] a=new char[512];
  14. while ((hr=fis.read(a))>0){
  15. String ss=new String(a,0,hr);
  16. System.out.println(ss);
  17. }
  18. fis.close();
  19. }
  20. }

输出流

只要创建了输出流,就相当于得到了一个空的水管。

同样,字节流接收字节byte,字符流接收字符char

  1. import java.io.FileOutputStream;
  2. import java.nio.charset.StandardCharsets;
  3. public class FileOutputTest {
  4. public static void main(String[] args) {
  5. FileOutputStream fos=null;
  6. try{
  7. //创建输出流
  8. fos=new FileOutputStream("E:\\Study\\Java\\UsingFilesAndIO\\src\\a.txt");
  9. //每次输出一个字符
  10. fos.write(13);
  11. fos.write(10);
  12. fos.write('f');
  13. //输出流读取字符集,用UTF-8将字符串转化成字节数组
  14. fos.write("可还行".getBytes(StandardCharsets.UTF_8));
  15. }
  16. catch (Exception ex){
  17. //处理异常
  18. System.out.println("出现异常");
  19. ex.printStackTrace();
  20. }
  21. finally {
  22. try {
  23. assert fos != null;
  24. fos.close();
  25. }
  26. catch (Exception ex){
  27. //处理异常
  28. ex.printStackTrace();
  29. }
  30. }
  31. }

文件复制

  1. import java.io.FileInputStream;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. public class Copy {
  5. //文件拷贝的本质就是对需要拷贝的文件进行及时的读写操作
  6. public static void main(String[] args) {
  7. try(
  8. FileInputStream fos=new FileInputStream("E:\\Study\\Java\\UsingFilesAndIO\\src\\a.txt");
  9. FileOutputStream fis=new FileOutputStream("E:\\Study\\Java\\UsingFilesAndIO\\src\\copy.txt");
  10. ){
  11. byte[] buff=new byte[512];
  12. int hasRead=0;
  13. while ((hasRead=fos.read(buff))>0){
  14. //保证读了多少内容就写内容
  15. fis.write(buff,0,hasRead);
  16. }
  17. }
  18. catch (IOException ex){
  19. System.out.println("确定文件是否存在");
  20. ex.printStackTrace();
  21. }
  22. }
  23. }

IO流读取写字符串的数据

  1. import java.io.ByteArrayInputStream;
  2. import java.io.IOException;
  3. import java.nio.charset.StandardCharsets;
  4. public class ArrayUsingTest {
  5. public static void main(String[] args) throws IOException {
  6. //将字符串转换为字符数组
  7. byte[] bytes="wy212".getBytes(StandardCharsets.UTF_8);
  8. ByteArrayInputStream bis=new ByteArrayInputStream(bytes);
  9. byte[] buff=new byte[512];
  10. int hasRead=0;
  11. while ((hasRead=bis.read(buff))>0){
  12. String str=new String(buff,0,hasRead);
  13. System.out.println(str);
  14. }
  15. }
  16. }
  1. import java.io.ByteArrayOutputStream;
  2. import java.io.IOException;
  3. import java.nio.charset.StandardCharsets;
  4. import java.util.Arrays;
  5. public class ArrayUsingTest2 {
  6. public static void main(String[] args) {
  7. try (
  8. //基于一个长度为32的数组创造了IO数组流,相当于得到了一个空的水管
  9. ByteArrayOutputStream bos=new ByteArrayOutputStream();
  10. ){
  11. //对于字节数组输出流而言,所有数据都被输出到底层的数组中
  12. byte[] a1="fucking".getBytes(StandardCharsets.UTF_8);
  13. bos.write(a1);
  14. System.out.println(Arrays.toString(a1));
  15. }
  16. catch (IOException ex){
  17. ex.printStackTrace();
  18. }
  19. }
  20. }

过滤流与缓冲流(要建立在已有的节点流的基础之上)

抽象基类 FilterInputStream FilterOutputStream FilterReader FilterWriter
缓冲流 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
打印流 PrintStream PrintWriter
转换流 InputStreamReader OutputStreamWriter
特殊流 DataInputStream DataOutputStream
对象流 ObjectInputStream ObjectOutputStream

内存速度远大于外设(磁盘,网络)速度

如果内存输出一个数据单元,然后外设就处理一个单元,必须等外设处理好数据单元之后,内存才会再输出下一个单元,必然会造成一个程序的性能浪费——此时就需要添加一个缓冲流

内存先把所有的数据输出到缓冲——缓冲中的数据留给外设慢慢处理

当你使用缓冲流的时候,必须使用flush()方法将数据”冲“到底层的物理设备中(想象一下奥利给在马桶里堆积)

当然,close()命令中也自带flash()命令

BufferedReader可以每次读取一行

包装流存在的意义

Java创造包装流来消除底层节点流的差异

输入流常用BufferedReader

  1. import java.io.BufferedReader;
  2. import java.io.FileReader;
  3. public class BufferTest {
  4. public static void main(String[] args) throws Exception{
  5. try (
  6. //作为过滤流,因此需要建立在其他流的基础之上
  7. BufferedReader bf=new BufferedReader(new FileReader("src/FileOutputTest.java"));
  8. ) {
  9. String line = null;
  10. while ((line = bf.readLine()) != null) {
  11. System.out.println(line);
  12. }
  13. }
  14. }
  15. }

输出流常用PrintStream

  1. import java.io.FileOutputStream;
  2. import java.io.IOException;
  3. import java.io.PrintStream;
  4. public class PrintStreamTest {
  5. public static void main(String[] args) throws IOException {
  6. PrintStream ps =new PrintStream(new FileOutputStream("src/copy.txt"));
  7. //输出到文件
  8. ps.println("离离原上谱");
  9. ps.println("葛涛宁YYDS");
  10. ps.close();
  11. //此时文本copy就会被输入上面的两行文字
  12. }
  13. }

转换流

负责将字节流转换为字符流

  • 理论上字节流比字符流功能更加强大
  • 但是有时,当文件中只需要使用字符时,需要该种转换

功能——传入一个字节流,就会传出字符流

特殊流

DateInputStream 提供了系列ReadXxx()专门用于读取不同类型的数据

DataOutputStream 提供了系列WriteXxx()专门用于写入不同类型的数据

(Xxx代表数据类型)

二者都是通过Java的内部格式来记录数据的

因此DataOutputStream输出的数据应该使用DateInputStream来读取

重定向标准输入输出

标准输出就是电脑屏幕

System.setOut()可以换掉标准输出的对象

举例:

  1. import java.io.FileOutputStream;
  2. import java.io.IOException;
  3. import java.io.PrintStream;
  4. public class Printout {
  5. public static void main(String[] args) throws IOException {
  6. System.setOut(new PrintStream(new FileOutputStream("src/wyd.txt")));
  7. //此时输出对象从屏幕改成了文件wyd
  8. System.out.println("f**k");
  9. System.out.println("wtf");
  10. System.out.println("language");
  11. }
  12. }

标准输入就是电脑键盘

System.setIn()可以换掉标准输入的对象

读取进程的数据

Ruhntime类有一个exec()方法可以用于运行平台上的程序,程序运行之后就变成了进程,因此该方法就返回运行的进程

Process就是进程,该对象提供了一些方法

  • InputStream getErrorStream()返回错误的流
  • InputStream getInputStream()返回普通的输入流
  • OutputStream getOutputStream()返回普通的输出流

(从Zeal粘的)

实例——简易的编译工具

  1. import javax.swing.*;
  2. import java.awt.*;
  3. import java.io.BufferedReader;
  4. import java.io.IOException;
  5. import java.io.InputStreamReader;
  6. import java.nio.charset.StandardCharsets;
  7. import java.util.Arrays;
  8. public class Compare {
  9. public static void main(String[] args) {
  10. //创建窗口
  11. JFrame JF=new JFrame("编译工具");
  12. //单例模式设计,只会产生一个实例
  13. Runtime rt=Runtime.getRuntime();
  14. //创建并添加JPanel
  15. JPanel JP=new JPanel();
  16. JF.add(JP,BorderLayout.NORTH);
  17. //创建多行文本域
  18. JTextArea jta=new JTextArea(10,80);
  19. jta.setEditable(false);
  20. jta.setBackground(Color.lightGray);
  21. //创建并添加单行的文本框
  22. JTextField jtf=new JTextField(80);
  23. JP.add(jtf);
  24. JButton jb=new JButton("编译");
  25. JP.add(jb);
  26. jb.addActionListener(e ->{
  27. String cmd = "javac -d . " + jtf.getText().trim();
  28. Process p;
  29. try {
  30. p = rt.exec(cmd);
  31. } catch (IOException ex) {
  32. throw new RuntimeException(ex);
  33. }
  34. StringBuilder sb = new StringBuilder();
  35. try(
  36. BufferedReader br=new BufferedReader(new InputStreamReader(p.getErrorStream()))
  37. ){
  38. String line;
  39. while ((line=br.readLine())!=null){
  40. sb.append(Arrays.toString(line.getBytes(StandardCharsets.UTF_8))).append("\n");
  41. }
  42. //没有读到错误信息
  43. if(sb.toString().length()==0){
  44. jta.setText("编译完成");
  45. }
  46. else {
  47. jta.setText(sb.toString());
  48. }
  49. }
  50. catch (IOException ex) {
  51. throw new RuntimeException(ex);
  52. }
  53. });
  54. JF.add(new JScrollPane(jta));
  55. JF.pack();
  56. JF.setVisible(true);
  57. JP.setVisible(true);
  58. }
  59. }