java-文件输入输出处理

---------------------------------------------------

1、File类

File类是IO包中唯一代表磁盘文件本身的对象,File类定义了一些与平台无关的方法来操作文件。通过调用File类提供的各种方法,能够完成创建、删除文件、重命名文件、判断文件的读写权限权限是否存在、设置和查询文件的最近修改时间等操作。

​ File类没有无参构造方法,最常用的是使用下面的构造方法来生成File对象(注意分隔符可以使用"/"和"",但是使用""必须写"\",因为涉及转义的问题):

File(String pathName) pathName指的是文件的路径名;

File.separator

在Windows下的路径分隔符(\)和在Linux下的路径分隔符(/)是不一样的,当直接使用绝对路径时,跨平台会报No Such file or diretory异常。

File中还有几个与separator类似的静态常量,与系统有关,在编程中应尽量使用。

//File.separator 表示不同系统下的路径分割符
File file = new File("D:"+File.separator+"test"+File.separator+"test1");
//File file = new File("D:/test/test1.txt");

2、创建文件

创建文件对象 File(String pathname)

//pathname 文件路径
File file = new File("D:/test/test1.txt");

创建文件 createNewFile()

File file = new File("D:/test");
//判断文件是否存在,不存在,创建
if(!file.exists()){
    try {
        //判断文件是否创建成功
        //createNewFile方法,会返回是否创建成功的结果,true成功,false失败
        if(file.createNewFile()){
            System.out.println("创建文件"+file.getName()+"成功");
        }else{
            System.out.println("创建文件"+file.getName()+"失败");
        }
    } catch (IOException e) {
        e.printStackTrace();
 }

3、创建目录(单级,多级)

mkdir()创建单级目录
mkdirs() 创建多级目录

创建单级目录 mkdir()

File dir = new File("D:/test/test1");//目前只有text文件夹
//判断目录是否存在,如果不存在则创建
if(!dir.exists()){
    //mkdir方法,创建目录,返回是否创建成功的结果
    //mkdirs方法,创建多级目录
    if(dir.mkdir()){
    	System.out.println("创建目录成功"); //生成test1文件夹
    }else{
    	System.out.println("删创建目录失败");
    }
}else{
    System.out.println("目录存在,不需要创建");
}

创建多级目录 mkdirs()

File dirs = new File("D:/test/test1/text1_1"); //目前只有text文件夹
//改变参数和方法即可
if(dirs.mkdirs()){
	System.out.println("创建目录成功"); //生成test1文件夹及子文件夹text1_1
}else{
	System.out.println("删创建目录失败");
}

4、删除文件或目录(只能删除单级空目录)

delete()

//存在则删除,不存在,提示
File file = new File("目录或文件路径"); 
if(file.exists()){
    // delete方法,删除文件或者目录,并会返回是否删除成功的结果,true-成功,false-失败
    //注意:删除目录,只能删除当前以及的目录,并且只能是空目录
    if(file.delete()){
   	 	System.out.println("删除文件或目录成功");
    }else{
    	System.out.println("删除文件或目录失败");
    }
}else{
	System.out.println("文件或目录不存在");
}
JAVA 复制 全屏

5、File类中常见方法

file.getName()文件名称
file.length() 文件大小
file.getPath() 文件路径
file.getAbsolutePath() 文件绝对路径

还有其他方法可以直接查看;

--------------------------------------------------

1、FileInputStream

1.1 初始化

FileInputStream(String name)
FileInputStream(File file)
//直接通过文件地址初始化
FileInputStream fis = new ileInputStream("D:/test/test1.txt");

//通过File对象初始化
File file = new File("D:/test/test1.txt");
FileInputStream fis = new FileInputStream(file)

1.2 获取文件大小

available()

FileInputStream fis = new ileInputStream("D:/test/test1.txt");
fis.available(); //文件大小

1.3 读取文件内容

read()读取一个字节(返回对应字节的ascii码值)
read(byte b[]) 根据字节缓冲数组的长度,进行读取(返回读取的字节数)

read()

//文件 D:/test/test1.txt 
内容
KH96abcdefghijk
FileInputStream fis = new ileInputStream("D:/test/test1.txt");
 while (true){
     //read() 方法:从输入流对象中,一次读取一个字节(返回的是对应字节的ascii码值,int类型)
     int hasRead = fis.read();

     //当读取到末尾,返回-1,代表文件读取结束
     if(hasRead == -1){
         break;
     }

     System.out.print((char) hasRead); 
     //打印文件中字符的ascii值
     //转化为字符:KH96abcdefghijk
 }

 //最后一定要关闭资源
 fis.close();

运行结果:

源文件的大小:15
KH96abcdefghijk

read(byte b[])

带缓冲字节数,读取文件内容,一次读取就不是一个字节,而是根据字节缓冲数组的长度,进行读取

错误案例

读取时通过read()来判断是否继续循环,读取到错误值

FileInputStream fis = new ileInputStream("D:/test/test1.txt");
//带缓冲字节数,根据字节缓冲数组的长度,进行读取
byte[] bytes = new byte[5];
//容易出错的判断方式:read()方式执行一次,就读取一个字节(没有保存,读完就扔,字节丢失),不可以作为判断条件
while(fis.read() != -1){
    //循环读取内容
    //带缓冲数组的读取,方法返回的是读取的字节数,不是读取的内容
    //每次读取的数据,是由缓冲字节数组长度决定,每次都是从上一次读取的位置后开始继续读取,每次都是将读取的内容依次放入缓存数组
    int hasRead = fis.read(bytes);
    System.out.println("读取的字节数:"+hasRead);
    System.out.println(new String(bytes));
    System.out.println("读取文件成功");
}
fis.close();

运行结果:

源文件的大小:15
读取的字节数:5
H96ab       //K丢失
读取文件成功
读取的字节数:5
defgh        //c丢失
读取文件成功
读取的字节数:2
jkfgh        //i丢失,并且还多出了上一次留下 dgh,这是因为没有读满缓冲字节数组,而造成的读取上一次的值
读取文件成功

正确案例

因为带字节缓冲数组返回的时读取到的长度,所以,用读取到的长度来判断是否要继续读取,和要写入多少个字节;

FileInputStream fis = new ileInputStream("D:/test/test1.txt");
//带缓冲字节数,根据字节缓冲数组的长度,进行读取
byte[] bytes = new byte[5];
//正确写法
int hasRead = 0;
while((hasRead = fis.read(bytes)) > 0){
    //每次读取的内容
    System.out.println(new String(bytes,0,hasRead));
}
fis.close();

运行结果:

源文件的大小:15
KH96a
bcdef
ghijk
// 没有丢失字节

1.4 资源关闭

close();

​ 在使用流资源的时候一定要关闭资源,否则会造成资源浪费;

放在try( ) 里面

​ JDK1.7以后,只需将资源初始化放在try()里面就可以不用手动关闭流资源;

2、FileOutputStream

2.1初始化

FileOutputStream(File file)
FileOutputStream(File file, boolean append)
FileOutputStream(String name)
FileOutputStream(String name, boolean append)

与FileInputStream类似,不过写入的文件不一定要存在,如果文件不存在,会自动创建一个空的文件;

2.2 写入方式 boolean append

boolean append 使用否以追加方式方式写入;

false(默认值,覆盖)
true(追加)

2.3 写入文件内容

write(byte b[])
write(byte b[], int off, int len)
String string = "KH96班,正在学习文件输出流,输出文件2";
//File file = new File("D:/test/test2.txt");

//JDK1.7以后,只需将资源初始化放在try()里面就可以不用手动关闭流资源,推荐使用;
try(FileOutputStream fos =  new FileOutputStream("D:/test/test2.txt",true)){

    //将字符串转成字节数组,写入目标文件
    fos.write(string.getBytes());

    //手动刷新缓冲区
    fos.flush();
    
}catch (IOException e){
    e.printStackTrace();
}

---------------------------------------------------

FileReader字符流读取文件,更适合用于读取文件,可以读取中文;

常用字符流类关系图

1、FileReader

1.1 初始化

FileReader(File file)
FileReader(String fileName)

1.2 读取文件内容

read()按单个字符读取
read(char cbuf[]) 按字符数组长度读取

案例:按字符数组读取

//test1.txt文件内容:FileWriter测试内容
try(
    //初始化字符读取流
    FileReader frd =   new FileReader("D:/test/test1.txt");
){
    //定义一个可变字符串对象
    StringBuilder sbd = new StringBuilder();

    //定义缓冲字符数组
    char[] chars = new char[5];

    int hasRead = 0; //读取到的字符长度
    while((hasRead = frd.read(chars))>0){
        sbd.append(new String(chars,0,hasRead));
        System.out.println("每次读取:"+sbd.toString());
    }

    //输出文件内容
    System.out.println("文件全部内容:"+sbd.toString());
    System.out.println("文件读取成功!");

} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

运行结果

每次读取:FileW
每次读取:FileWriter
每次读取:FileWriter测试内容
文件全部内容:FileWriter测试内容
文件读取成功!

2、FileWriter

2.1 初始化

FileReader(String fileName)
FileReader(File file)

2.2 写入文件内容

write(String str)
write(String str, int off, int len)
write(char cbuf[])
write(char cbuf[], int off, int len)

案例:字符流直接写入字符串

 //FileWriter 字符流写文件基本用法,可以直接写字符
      
try( FileWriter fwr=  new FileWriter("D:/test/test2.txt")){

    //定义写入文件
    String string = "KH96,正在学习字符流写入文件";

    //直接写入目标文件
    fwr.write(string);

    //刷新缓冲区
    fwr.flush(); //一定要刷新缓冲区

    System.out.println("字符流写入成功!!!");
}catch (Exception e){
    e.printStackTrace();
}
JAVA 复制 全屏

运行结果

字符流写入成功!!!

-----------------------------------------------------

1、BufferedReader

BufferedReader高效字符流读取文件基本用法,自带缓冲区,读取文件效率高,支持逐行读取;

1.1 初始化

BufferedReader(Reader in)默认缓冲字符数组(大小8192)
BufferedReader(Reader in, int sz) 自定义缓冲字符数组大小

1.2 读取文件内容

buffer1.txt文件内容

张三,23
李四,34
王五,34

逐行读取案例

try(BufferedReader bfrd = new BufferedReader(new FileReader("D:/test/buffer1.txt"))){
    //使用逐行读取方式,读取文件
    String readLinestr = bfrd.readLine();

    //当读取内容为null的时候跳出循环
    while(readLinestr != null){
        System.out.println(readLinestr);
        //继续读取下一行
        readLinestr = bfrd.readLine();
    }

    System.out.println("逐行读取成功");

}catch (Exception e){
    e.printStackTrace();
}

运行结果

张三,23
李四,34
王五,34
逐行读取成功

1.3 默认缓冲区

//默认缓冲区的大小为:8192个字符

源码

public BufferedReader(Reader in) {
    this(in, defaultCharBufferSize); //使用默认字符数组容量
}

private static int defaultCharBufferSize = 8192; //默认最大值为8192

2、BufferedWriter

BufferedWriter高效字符流写入文件基本用法,可以直接写整行,还可以换行(newLine());

2.1 初始化

BufferedWriter(Writer out)默认缓冲字符数组(大小8192)
BufferedWriter(Writer out, int sz) 自定义缓冲字符数组大小

2.2写入文件内容

try(BufferedWriter bfwt = new BufferedWriter(new FileWriter("D:/test/buffer2.txt"))){
    //写入内容
    String string = "KH96,正在学习高效字符流写入";
    //写入
    bfwt.write(string);
    //换行
    bfwt.newLine();
    bfwt.write(string+",新的一行");
    
    //刷新缓冲区
    bfwt.flush();

    System.out.println("高效字符写入完成");

}catch (Exception e){
    e.printStackTrace();
}

3、InputStreamReader

InputStreamReader(InputStream in)默认本地字符集
InputStreamReader(InputStream in, String charsetName) 自定义字符集

BufferedReader 通过InputStreamReader可以指定字符集读取文件的内容;

  try(
      //InputStreamReader提供了一个指定字符集的构造方法,创建输入字符对象,必须指定字符集跟文件字符集一致
      BufferedReader bfrd = new BufferedReader(new InputStreamReader(new FileInputStream("D:/test/end1.txt"),"gbk"))
  ){
      //使用逐行读取方式,读取文件
      String readLinestr = bfrd.readLine();

      //循环读取,读取到文件末尾,返回null
      while(readLinestr != null){
          System.out.println(readLinestr);
          //继续读取下一行
          readLinestr = bfrd.readLine();
      }
      System.out.println("逐行读取成功");

  }catch (Exception e) {
      e.printStackTrace();
  }

4、 OutputStreamWriter

OutputStreamWriter(OutputStream out)默认本地字符集
OutputStreamWriter(OutputStream out, String charsetName) 自定义字符集

BufferedWriter 通过OutputStreamWriter可以指定字符集写入文件的内容;

  try(
        BufferedWriter bfrwt = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:/test/end1.txt"),"gbk"))
        ){
            String str = "测试指定文件字符集为gbk写入";
            bfrwt.write(str);

            System.out.println("文件写入完成!!!");

        }catch (Exception e) {
            e.printStackTrace();
        }

----------------------------------------------------

1、实例化

DataInputStream(InputStream in)参数是一个字节输入流
DataOutputStream(OutputStream out) 参数是一个字节输出流

演示

DataInputStream dis = new DataInputStream(new FileInputStream("D:/test/girl.jpg"));
DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:/test/girl2.jpg"));

2、举例

复制图片

 try(
  DataInputStream dis = new DataInputStream(new FileInputStream("D:/test/girl.jpg"));
  DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:/test/girl2.jpg"));
 ){	

     //字符缓冲区
     byte[] bytes = new byte[10];

     //读取长度
     int hasread = 0;

     while((hasread = dis.read(bytes))>0){
         dos.write(bytes,0,hasread);
     }

     //刷新缓冲区
     dos.flush();

     System.out.println("图片复制成功");

 }catch (Exception e){
     e.printStackTrace();
 }

----------------------------------------------------

序列号

  • 序列号是序列化和反序列化的唯一标识,是一个长整型数值;
  • 如果类中不自己定义序列号,系统会自动生成一个序列号;
  • 当一方实体类发生改变,而调用方的序列号是不会跟着改变的,不知道对象已修改,会导致两边序列号不一致,反序列化失败;
  • 所以要求必须手动生成一个序列号;
  • 手动生成序列号后,可以解决目标类发生改变,不影响接口调用,对象可以正确序列化,不过对象修改的属性返序列化后没有值;

序列化对象类

//如果要支持序列化操作必须实现序列化接口
//账户类
public class Account implements Serializable {
	//手动生成序列号
    private static final long serialVersionUID = 2116137267832764072L;
    
    //账户名
    private  String aname;

    //账户密码
    private String apwd;
    
    //set,get方法省略
    
    @Override
    public String toString() {
        return "Account{" +
                "aname='" + aname + '\'' +
                ", apwd='" + apwd + '\'' +
                '}';
    }
}    

IDEA如何生成序列号

序列化

使用ObjectOutputStream 类的 writeObject(Object obj)方法

//序列化对象,写入文件
public static void xlhAccount() throws IOException {
    Account account = new Account("KH96","12345");

    //使用对象输出流,将内存中的对象写入到文件
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/test/account.txt"));
    
    //直接写入对象
    oos.writeObject(account);

    oos.close();
    System.out.println("序列化对象写入成功");
}

序列化结果

反序列化

使用 ObjectInputStream 类的 readObject()方法

//反序列化目标对象读取写入序列化的文件,进行反序列化,变为写入的那个目标对象
public static void fxlhAccount() throws IOException, ClassNotFoundException {
    //使用对象输入流,读入写入了序列化对象的文件
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/test/account.txt"));
    
    Account account = (Account) ois.readObject();
    ois.close();
    
    //输出目标对象
    System.out.println(account.toString());

    System.out.println("读取序列化对象,反序列化成功");

}

反序列化结果

Account{aname='KH96', apwd='12345'}
读取序列化对象,反序列化成功

当类发生改变

改变后的序列化对象

//账户类
public class Account implements Serializable {
	//手动生成序列号
    private static final long serialVersionUID = 2116137267832764072L;
    
    //账户名
    private  String aname;
    
    //账户密码
    private String apwd;

    //添加手机
    private  String atel;
    
    //set,get方法省略
    
    @Override
    public String toString() {
        return "Account{" +
                "aname='" + aname + '\'' +
                ", apwd='" + apwd + '\'' +
                ", atel='" + atel + '\'' +
                '}';
    }
}
JAVA 复制 全屏

反序列化结果

Account{aname='KH96', apwd='12345', atel='null'}
读取序列化对象,反序列化成功
posted @ 2022-12-01 15:27  hanease  阅读(305)  评论(0编辑  收藏  举报