javaI.O流

Input、output Stream流

java File文件操作

在了解输入输出流之前,先总结一下java文件相关操作

  • 相对路径

  • 相对某个基准⽬录或者⽂件的路径, ./ 表示当前路径; …/ 表示上级⽬录

  • 绝对路径

  • 存储在硬盘上的真正路径

  • windows 中的路径

  • windows中以 \ 作为 文件目录分割符

  • 在java中,需要用到 \\ 表示, 第一个 \ 用来转义

  • Linux 和 Mac 中的路径

  • / 表示 Linux或者Mac的路径分隔符

  • 如果是Java代码在Linux或者Mac下写某个⽂件的话直接写 / 就可以了

File文件类

  1. File类表示磁盘中存在的⽂件和⽬录,对⽂件的和⽬录的增删改查

  2. File类的包名是java.io,也实现了Serializable, Comparable两⼤接⼝以便于其对象可序列化 和⽐较

  3. File.separator ⽬录分隔符,在不同的系统下不⼀样, windows和 mac /Linux,当不知道系统分割符的时候,可以使用以代替手写

    常见构造函数:

//路径和⽂件拼接
public File(String pathname)
//⽗路径,⼦路径
public File(String parent, String child)
//测试⽅法:获取⽂件的路径,即new File构造函数传⼊的路径
String getPath()

常用方法:

  public static void main(String[] args) {

      String dir = "C:\\Users\\22496\\Desktop";
      String name = "a.txt";
   
      File file1 = new File("C:\\Users\\22496\\Desktop\\b.txt");
  	try {
          file1.createNewFile();  // 创建文件
      } catch (IOException e) {
          e.printStackTrace();
      }
      File file =new File(dir,name);

      System.out.println("文件路径:"+file.getPath());
      System.out.println("系统分割符:"+File.separator);
      // 判断文件是否存在
      System.out.println(file.exists());
      //  ⽬录中的⽂件和⽬录的名称所组成字符串数组
      String[] filelist = file.list();
      System.out.println(Arrays.toString(filelist));

      //mkdir() 创建一个指定的目录,
      File mkdirFile = new File(dir+File.separator+"mkdir1");
      mkdirFile.mkdir();

      // mkdir() 多级目录时, 一个目录都不会创建
//        File mkdirFile1 = new File(dir+File.separator+"mkdir"+File.separator+"mkdir2.txt");
//        mkdirFile1.mkdir();

      //mkdirs() 创建多个层级的⽬录
      File mkdirFile3 = new File(dir+File.separator+"mkdir"+File.separator+"mkdir2");
      mkdirFile3.mkdirs();

       //判断是否是目录文件,即文件夹
      System.out.println(mkdirFile3.isDirectory());
      
      //判断是否是文件
      System.out.println(file.isFile());
      
      //删除文件夹
      file1.delete();
      
  }

文件目录就是文件夹;

可以理解为:

mkdirs( ) 和mkdir( ) 都只能创建windows上的文件夹,其他文件不可,例如 .txt,.DOC文件等,当你把文件路径写成"c:\ \ Desktop\ \ a \ \ b.txt " 也只会创建 名为 b.txt 的文件夹 ;

mkdirs( ) 可以创建多级 ,多级包括一级目录,所以使用中推荐使用 mkdirs( );

delete( )

删除文件夹或者文件,删除路径末端的文件夹或者文件,若是文件夹必须为空才会删除; 例如文件路径为"c:\ \ Desktop\ \ a \ \ b.txt "

只会删除 b.txt; 若对"c:\ \ Desktop\ \ a " 路径删除,无效,a目录下还有 b.txt 文件

File 操作中,对已经删除,或者已经新建的文件夹或者文件,再次删除或者新建,程序会直接return,不操作;

createNewFile() 创建文件时,如果不写文件后缀,默认是 文件类型的文件

  • 什么是IO?

    • input : 输出流 内存——>外界设备

    • output : 输入流 外界设备 ——>内存

    • 输出流 都可以帮我们在当目的操作对象不存在时,创建目的对象,例如文件,数组等;当为文件时,只会创建文件,不会创建目录,new 时 ,若传入相对路径进行构造,则文件会创建在该项目 Module 目录下;

      输出流 new 文件对象时,只能是文件,若为目录,则报文件找不到的异常

  • java 把数据分为两类

    • 字符流 : 处理字符相关,如处理⽂本数据(如txt⽂件), Reader/Writer
    • 字节流 : 处理字节相关,如声⾳或者图⽚等⼆进制,InputStream/OutputStream

    字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,⼀次可能读多个

    字节

    字节流可以处理⼏乎所有⽂件,字符流只能处理字符类型的数据

字节流

字节流,一个字节一个字节的读,

inputStream 输入流
  • InputStream是输⼊字节流的⽗类,它是⼀个抽象类(⼀般⽤他的⼦类)

    int read()

    讲解:从输⼊流中读取单个字节,返回0到255范围内的int字节值,字节数据可直接转换为int类

    型, 如果已经到达流末尾⽽没有可⽤的字节,则返回-1

    int read(byte[] buf)

    讲解:从输⼊流中读取⼀定数量的字节,并将其存储在缓冲区数组buf中, 返回实际读取的字节

    数,如果已经到达流末尾⽽没有可⽤的字节,则返回-1

    long skip(long n)

    讲解:从输⼊流中跳过并丢弃 n 个字节的数据。

    int available()

    讲解:返回这个流中有多少个字节数,可以把buf数组⻓度定为这个

    void close() throws IOException

    讲解:关闭输⼊流并释放与该流关联的系统资源

  • 常见子类

    • FileInputStream

      具体对文件进行操作的文件字节输入流

      构造函数:

      //传⼊⽂件所在地址
      public FileInputStream(String name) throws FileNotFoundException
      //传⼊⽂件对象
      public FileInputStream(File file) throws FileNotFoundException
      

      使用:

             public static void main(String[] args) throws IOException {
      
              String dir = "C:\\Users\\22496\\Desktop";
              String name = "a.txt";
              File file =new File(dir,name);
              FileInputStream fileInputStream = null;
              try {
                  fileInputStream = new FileInputStream(file);
              } catch (FileNotFoundException e) {
                  e.printStackTrace();
              }
              test(fileInputStream);
          }
      
      
         public static void test(FileInputStream fileInputStream) throws IOException {
      
      //        long l=fileInputStream.skip(2);
      //        System.out.println(l);
      //        //read() 会读取一个字节 ;返回读取到的内容编码;汉字>1字节 会乱码
      //        int read = fileInputStream.read();
      //        System.out.println((char) read);
      
              //每次读取b 的长度 ;若长度为0, 不读取,返回0;
             // read(byte [] b ) 返回读取到的字节长度
              byte []b =new byte[1024];
              while(fileInputStream.read(b)!=-1){
                  int length=fileInputStream.read(b);
                   System.out.println(length); //  -1
                  System.out.println(new String(b,0,length));
              }
             
             //关闭资源
      		fileInputStream.close();
          }
      
      
      

      byte 数组在读取的时候,是在原有数组的基础上依次替换元素,若最后只剩1个字节了,我们只替换一个字节元素,那我们在 转String的时候,就会把后面的字节元素读出来,所以在 new String(b,0,length) 时,加上范围参数;

outputStream 输出流
  • OutputStream是输出字节流的⽗类,它是⼀个抽象类

void write(int b)

讲解:将指定的字节写⼊输出流

void write(byte[] b)throws IOException

讲解:将b.length个字节的byte数组写⼊当前输出流

void flush() throws IOException

讲解:write是写到缓冲区中,可以认为是内存中,当缓冲区满时系统会⾃动将缓冲区的内容写⼊

⽂件,但是⼀般还有⼀部分有可能会留在内存这个缓冲区中, 所以需要调⽤flush空缓冲区数据。

void close() throws IOException

讲解:关闭输⼊流并释放与该流关联的系统资源

  • 常见子类

FileOutputStream

⽂件字节输出流,对⽂件数据以字节 的形式进⾏输出的操作

构造函数:

//传⼊输出的⽂件地址
public FileOutputStream(String name)
//传⼊⽬标输出的⽂件对象
public FileOutputStream(File file)
//传⼊⽬标输出的⽂件对象, 是否可以追加内容
public FileOutputStream(File file, boolean append)

使用:

 public static void main(String[] args) throws IOException {
        String dir = "C:\\Users\\22496\\Desktop";
        String name = "a.txt";
        String target = "b.txt";
        File file = new File(dir, name);
        InputStream inputStream = new FileInputStream(file);
        //会⾃动创建⽂件,但是不会创建多级⽬录下的⽂件
        OutputStream outputStream = new
                FileOutputStream("C:\\Users\\22496\\Desktop\\" + target);
        // true,不覆盖⽂件,追加数据 若要写入换行,加 \n 
        //OutputStream outputStream = new
//        FileOutputStream("C:\\Users\\22496\\Desktop\\"+target,true);
        //testOutBuf(inputStream ,outputStream);
        testOut(inputStream, outputStream);
    }

    //单个字节读取,中⽂会有问题
    public static void testOut(InputStream inputStream, OutputStream
            outputStream) throws IOException {
        int value = 0;
        while (value != -1) {
            value = inputStream.read();
            outputStream.write(value);
        }
        //最后记得关闭流
        inputStream.close();
        outputStream.close();
    }

    public static void testOutBuf(InputStream inputStream, OutputStream
            outputStream) throws IOException {
        byte[] buf = new byte[1024];
        int length;
        while ((length = inputStream.read(buf)) != -1) {
            outputStream.write(buf, 0, length);
        }
        //最后记得关闭流
        inputStream.close();
        outputStream.close();
    }
  

Buffer 输入输出流
  • 什么是缓冲 Buffffer 它是内存空间的⼀部分,在内存空间中预留了⼀定的存储空间,这些存储空间

    ⽤来缓冲输⼊或输出的数据,这部分空间就叫做缓冲区,缓冲区是具有⼀定⼤⼩的,

  • 缓冲 cache ,解决磁盘与内存速度不匹配的问题,加入缓冲可大大提高读写效率

BufffferedInputStream 和 BufffferedOutputStream

BufffferedInputStream 缓冲字节输⼊流

默认缓冲区⼤⼩是8k = 8*1024 字节

构造函数:

//对输⼊流进⾏包装,⾥⾯默认的缓冲区是8k
public BufferedInputStream(InputStream in);
//对输⼊流进⾏包装,指定创建具有指定缓冲区⼤⼩的
public BufferedInputStream(InputStream in,int size);

常用方法:

/从输⼊流中读取⼀个字节
public int read();
//从字节输⼊流中给定偏移量处开始将各字节读取到指定的 byte 数组中。
public int read(byte[] buf,int off,int len);
//关闭释放资源,关闭的时候这个流即可,InputStream会在⾥⾯被关闭
void close();

BufffferedOutputStream 缓冲字节输出流

构造函数:

//对输出流进⾏包装,⾥⾯默认的缓冲区是8k
public BufferedOutputStream(OutputStream out);
//对输出流进⾏包装,指定创建具有指定缓冲区⼤⼩的
public BufferedOutputStream(OutputStream out,int size)

常用方法:

 //向输出流中输出⼀个字节
 public void write(int b);
 //将指定 byte 数组中从偏移量 off 开始的 len 个字节写⼊缓冲的输出流。
 public void write(byte[] buf,int off,int len);
 //刷新此缓冲的输出流,强制使所有缓冲的输出字节被写出到底层输出流中。
 public void flush();
 //关闭释放资源,关闭的时候这个流即可,OutputStream会在⾥⾯被关闭, JDK7新特性try(在这
⾥声明的会⾃动关闭){}
 void close();

需求 把 a.txt 文件里的内容拷贝到 b.txt

 public static void main(String[] args) throws Exception {

        FileInputStream fi =new FileInputStream("C:\\Users\\22496\\Desktop\\a.txt");
        BufferedInputStream bi=new BufferedInputStream(fi);

        FileOutputStream fo=new FileOutputStream("C:\\Users\\22496\\Desktop\\b.txt");
        BufferedOutputStream bo=new BufferedOutputStream(fo);

        int size;
        byte [] b =new byte[1024];
        while((size=bi.read(b))!=-1){
            bo.write(b,0,size);

        }
        //刷新缓存区,确保全部写入磁盘;不用显示写出来;close()包含flush()
        // bo.flush();
        //关闭的时候只需要关闭最外层的流就⾏了
        // 关闭顺序 后开先关, 如果A依赖B,先关闭B
        bo.close();
        bi.close();

    }

BufffferedOutputStream在不调⽤close()的情况下,缓冲区不满,⼜需要把缓冲区的内容写⼊到⽂件或通过⽹络发送到别的机器时,才需要调⽤flush

在关闭流之前 ,不能删除流所依赖得文件, 正确的顺序是,先close(),再delete(); 若顺序相反,不删除,也不关闭流,也不报错;

	File file = new File("C:\\Users\\22496\\Desktop\\c.txt");
  InputStream inputStream = new FileInputStream(file);
  inputStream.close();
  file.delete();

//        删除失败
//   	  file.delete();
//        inputStream.close();
//        System.out.println(file.getName());
 

BuffferedReader 和 BufferedWriter

BuffferedReader 有一个读一行的方法 (这里的一行指的是遇到换行符结束); readLine( );

BufferedWriter 使用与Writer 类似,追加写入时,参数true,写在 : Writer w = new FileWriter(“C:\Users\22496\Desktop\b.txt”,true); BufferedOutputStream同理

        Reader r = new FileReader("C:\\Users\\22496\\Desktop\\b.txt");
        BufferedReader br = new BufferedReader(r);

        String str = null;
//  读一行,读到文件末尾返回null;
        while((str=br.readLine())!=null){
            System.out.println(str);
        }

字符流

字符流,一个字符一个字符的读,

字符流操作跟字节流差不多,只是每次读取的内容不一样,字符流 int read(char cbuf[]) char 数组,字节流是byte数组,输出字符流中的 write() 中可以直接传String 类型,char [] 类型 ,

Reader

Reader是输⼊字符流的⽗类,它是⼀个抽象类, 部分库不推荐使⽤Reader/Writer,所以简单了解

即可

int read()

讲解:⼀个字符⼀个字符的读,只能⽤来操作⽂本(不能写图⽚ ⾳频 视频)

int read(char cbuf[])

讲解:从输⼊字符流中读取⼀定数量的字符,并将其存储在缓冲区数组cbuf中, 返回实际读取的字符

数,如果已经到达流末尾⽽没有可⽤的字节,则返回-1

void close() throws IOException

讲解:关闭输⼊流并释放与该流关联的系统资源

常见子类

FileReader ⽤来读取字符⽂件的实现类

构造


public FileReader(String fileName) throws FileNotFoundException {
 super(new FileInputStream(fileName));
}

public FileReader(File file) throws FileNotFoundException {
 super(new FileInputStream(file));
}

使用:


    public static void main(String[] args) throws Exception {

        String url = "C:\\Users\\22496\\Desktop\\b.txt";

        File file = new File(url);

        Reader fileReader = new FileReader(file);

        char[] b = new char[4];

        //读取单个字符
//        int ch;
//        while((ch=fileReader.read())!=-1){
//            System.out.print( (char) ch);
//        }

        //读出多个字符
        int ch = -1;
        while((ch=fileReader.read(b))!=-1){
            System.out.print(new String(b,0,ch));
        }


    }
Writer

直接看使用吧:

  public static void main(String[] args) throws IOException {

        Writer writer = new FileWriter("C:\\Users\\22496\\Desktop\\b.txt",true);
      
      // write() 也可传 char数组 ,String 有 getChar() 方法直接返回char数组
        writer.write("哈哈!");
        // 换行 写入
        writer.write("\n嘻嘻!");
        if(writer!=null)
            writer.close();

    }

转换流

InputStreamReader 和OutputStreamWriter,这两个类是只能将字节流转换为字符流的类,不能反向转换;InputStreamReader 可以将一个InputStream转换为Reader,OutputStreamWriter可以将一个OutputStream转换为Writer。

 public static void test1(String path) throws IOException {
 
 //读取字节流
 InputStream in = new FileInputStream(path);
 //将字节流向字符流的转换。
 InputStreamReader isr = new InputStreamReader(in,"GBK");
 
 //创建字符流缓冲区
 BufferedReader reader = new BufferedReader(isr);//缓冲
 //String line;
 //while((line = reader.readLine())!=null){
 // System.out.println(line);
 //}
 //isr.close();
 int size;
 char[] cbuf = new char[1024];
 while ((size = reader.read(cbuf, 0, cbuf.length)) != -1) {
 System.out.println(new String(cbuf, 0, size));
 }
 reader.close();
 }

打印流

主要包括字节打印流(PrintStream)和字符打印流(PrintWriter)。打印流提供了非常方便的打印功能,可以打印任何的数据类型。如:小数、整数、字符串等。

  • PrintStream和PrintWriter都属于输出流,分别针对输出字节和字符。

  • PrintStream和PrintWriter提供了重载的print()、println()方法用于多种数据类型的输出。

  • PrintStream和PrintWriter不会抛出异常,用户通过检测错误状态获取错误信息。

  • PrintStream和PrintWriter有自动flush 功能。

  • PrintStream 构造方法:

    • PrintStream(OutputStream out)
    • PrintStream(OutputStream out, boolean auotflush)
    • PrintStream(OutputStream out, boolean auotflush, String encoding)
  • PrintWriter 构造方法

    • PrintWriter(OutputStream out)
    • PrintWriter(OutputStream out, boolean autoflush)
    • PrintWriter(Writer out)
    • PrintWriter(Writerout, boolean autoflush)

    ​ 其中autoflush控制在Java中遇到换行符(\n)时是否自动清空缓冲区,encoding是指定编码方式。

    关于 autoflush 自动清空缓冲区

    PrintWriter即使遇到换行符(\n)也不会自动清空缓冲区,只在设置了autoflush模式下使用了println方法后才自动清空缓冲区。PrintWriter相对PrintStream最有利的一个地方就是println方法的行为,在Windows的文本换行是"\r\n",而Linux下的文本换行是"\n",如果希望程序能够生成平台相关的文本换行,而不是在各种平台下都用"\n"作为文本换行,那么就应该使用PrintWriter的println方法时,PrintWriter的println方法能根据不同的操作系统而生成相应的换行符。

使用:

// 控制台打印 
		PrintWriter out = new PrintWriter(System.out);
		// 向屏幕上输出
		out. println("Hello World!");
		out.close();	//如果此句不写,则没有内容,跟PrintStream有区别

//在文件中打印
		PrintWriter out = null;
		File f = new File("c:\\temp.txt");
		try {
			// 由FileWriter实例化,则向文件中输出
            // 也可以直接用文件实例化
			out = new PrintWriter(new FileWriter(f));
		} catch (IOException e) {
			e.printStackTrace();
		}
		out.print("Hello World!" + "\r\n");
		out.close();

对象流

对象序列化

Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。通过将对象序列化,可以方便的实现对象的传输及保存。

​ Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等,而这些数据都会以二进制序列的形式在网络上传送。那么当两个Java进程进行通信时,实现进程间的对象传送,就需要Java序列化与反序列化了。换句话说,一方面,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象。

在Java中提供了ObjectlnputStream与ObjectOutputStream这两个类用于序列化对象的操作。

ObjectlnputStream 提供反序列化, ObjectOutputStream 提供序列化

在实现对象序列化之前,要求对象实现java.io.Serializable接口,但Serializable接口中没有定义任何方法,仅仅被用作一种标记,以被编译器作特殊处理。

使用:

	// 以下方法为序列化对象方法,将对象保存在文件之中
	public static void serialize(File f) throws Exception{
		OutputStream outputFile = new FileOutputStream(f);
		ObjectOutputStream cout = new ObjectOutputStream(outputFile)
		cout.writeObject(new Person("张三",25));
		cout.close();
	}

	// 以下方法为反序列化对象方法,从文件中读取已经保存的对象
	public static void deserialize(File f) throws Exception {
		InputStream inputFile = new FileInputStream(f);
		ObjectInputStream cin = new ObjectInputStream(inputFile);
		Person p = (Person) cin.readObject();
		System.out.println(p);
	}

	public static void main(String args[]) {
		File f = new File("SerializedPerson");
		serialize(f);
		deserialize(f);
	}

serialVersionUID 常量

​ 在对象进行序列化或反序列化操作的时候,要考虑 JDK 版本的问题。如果序列化的 JDK 版本和反序列化的 JDK 版本不统一,则可能造成异常。因此在序列化操作中引入了一个serialVersionUID 的常量来验证版本的一致性。在进行反序列化时,JVM 会把传来的字节流中的 serialVersionUID 与本地相应实体(类)的serialVersionUID 进行比较。如果相同就认为是一致的,可以进行反序列化,否则就会出现反序列化版本不一致的异常

transient关键字

​ 如果不希望类中的属性被序列化,可以在声明属性之前加上transient关键字。如下所示,下面的代码修改自前面所用到的Person.java程序,在声明属性时,前面多加了一个transient关键字

private transient String name;

private transient int age;

注意:

序列化细节:

​ 1) 被序列化的类的内部的所有属性,必须是可序列化的

​ 2) static,transient修饰的属性,不可以被序列化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值