File、IO流及序列化

本文探讨了GBK编码到UTF-8的转换过程中可能出现的乱码问题,并通过示例展示了如何正确使用Java的字符串编解码方法,包括File类、IO流、对象序列化等,重点讲解了PrintWriter和字符集设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、File

一、编解码

  1. GBK 2个字节转换成UTF-8 3个字节,再转换成GBK,乱码。
  2. 编解码时可指定编解码方式:
 public static void main(String[] args) throws UnsupportedEncodingException {
        String s = new String("123今天上课了了");
        byte[] s1 = s.getBytes();
        System.out.println(Arrays.toString(s1));

        String s2 = new String(s1, "UTF-8");
        System.out.println(s2);
        String s4 = new String(s1,"GBK");
        System.out.println(s4);
        byte[] s5 = s4.getBytes("GBK");
        String s6 = new String(s5);
        System.out.println(s6);

        System.out.println("\nGBK2个字节转换成UTF-8 3个字节,再转换成GBK,乱码");
        byte[] s3 = s.getBytes("GBK");
        System.out.println(Arrays.toString(s3));
        String s7 = new String(s3,"UTF-8");
        System.out.println(s7);
        byte[] s8 = s7.getBytes();
        String s9 = new String(s8,"GBK");
        System.out.println(s9);

    }

二、File类及相关方法

1.构造方法及常用方法;

 public static void main(String[] args) throws IOException {
        File f = new File("src/Pointer/File/aa.txt");
        if(!f.exists()){
        f.createNewFile();//创建
        }
        boolean a = f.isFile();
        boolean b = f.isDirectory();
        System.out.println(a + " " + b);

        File f1 = new File("bb\\cc\\dd");
        if (!f1.exists()){
            f1.mkdirs();//创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。 
        }

        long l = f.length();//文件长度(大小)
        String s = f.getAbsolutePath();//获取绝对地址
        String n = f.getName();//文件名
        System.out.println(l);
        System.out.println(s);
        System.out.println(n);
        long l1 = f.lastModified();//最近一次的修改时间,返回的时long类型的毫秒值
        
        Date d = new Date(l1);
        DateFormat d1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String s2 = d1.format(d);
        System.out.println(n + "的最近修改时间为:" + s2);

        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(l1);
        Date d2 = c.getTime();//返回Date类型
        System.out.println("Calendar实现:"+d1.format(d2));
        }
  1. 删除操作;
System.out.println("以下是删除操作:--------");
        //System.out.println("delete删除文件或者空目录,不可逆:" + f.delete());
        File f2 = new File("bb");
        del(f2);
        
   public static void del(File f){//递归删除文件夹
        File[] file = f.listFiles();
        for(File ff : file){
            if (ff.isDirectory()){
                if (ff.listFiles() != null) {
                    del(ff);
                }
            }
            ff.delete();
        }
        f.delete();
    }
  1. listFiles及其过滤器;
//FileFilter()
       File f3 = new File("src/Set");
       File[] file1 = f3.listFiles(new FileFilter() {
           @Override
           public boolean accept(File f) {
               boolean b = f.isFile();
               boolean c = !f.getName().endsWith(".java");//保留.java文件
               return b&&c;
           }
       });
       for(File ff : file1){
           ff.delete();
       }

       // FilenameFilter()
        File[] file2 = f3.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                File f = new File(dir,name);//创建文件
                boolean c = f.getName().endsWith(".java");
                return c;
            }
        });
        for(File ff : file2){
            ff.delete();
        }

二、IO流

输入流输出流
InputOutput
字节流字符流
InputStream OutputStreamReader Writer
FileInputStream FileOutputSttreamFileReader FileWriter
BufferedInputStream BufferedOutputStreamBufferedReader BufferedWriter

一、PrintWriter

常用方法就不过多描写了,主要讲PrintWriter及其相关的输入输出类。
在这里插入图片描述
PrintWriter 可以指定字符集,也可以自动刷新,那么怎样实现二者兼备,同时支持文件末尾添加数据呢?
引入OutputStreamWriter 和 InputStreamReader

FileOutputSttreamtrue -> 可在文件末尾添加
OutputStreamWriter“GBK” -> 指定字符集
PrintWritertrue -> println自动刷新
FileInputStream
InputStreamReader“GBK” -> 指定字符集
BufferedReader

代码如下:

public static void main(String[] args) throws IOException {
        File f = new File("src/Pointer/File/IO/a.txt");
        //PrintWriter pw = new PrintWriter(f,"GBK");
        //pw.println("中国YYDS");
        //pw.flush();

        /*FileOutputStream fos = new FileOutputStream(f,true);//文尾添加
        PrintWriter pw1 = new PrintWriter(fos,true);//自动刷新
        pw1.println("今天回家吃饭吗,宝贝");
        pw1.close();
        fos.close();*/

        FileOutputStream fos1  = new FileOutputStream(f,true);
        OutputStreamWriter osw = new OutputStreamWriter(fos1,"GBK");//指定字符集
        PrintWriter pw2 = new PrintWriter(osw,true);
        pw2.println("嘭");
        pw2.print(100000);
        pw2.close();
        osw.close();;
        fos1.close();

        FileInputStream fis = new FileInputStream(f);
        InputStreamReader isr = new InputStreamReader(fis,"GBK");//指定字符集
        BufferedReader br = new BufferedReader(isr);
        String s;
        while ((s = br.readLine()) != null){
            System.out.println(s);
        }
        isr.close();
        fis.close();

    }

三、对象序列化

序列化操作

  1. ⼀个对象要想序列化,必须满⾜两个条件:
    该类必须实现 java.io.Serializable 接⼝, Serializable 是⼀个标记接⼝,不实现此接⼝的类将不会使任何状态序列化或反序列化,会抛出 NotSerializableException
    该类的所有属性必须是可序列化的。如果有⼀个属性不需要可序列化的,则该属性必须注明是瞬态的,使⽤ transient 关键字修饰。
public class Employee implements java.io.Serializable {
 public String name;
 public String address;
 public transient int age; // transient瞬态修饰成员,不会被序列化
 public void addressCheck() {
 System.out.println("Address check : " + name + " -- " + address);
 }
}

ObjectOutputStream 和 ObjectInputStream
将对象作为流存入文件

public static void main(String[] args) throws ParseException, IOException, ClassNotFoundException {
        Date d1 = new Date();
        DateFormat df = new SimpleDateFormat("yy-MM-dd");
        String s = "2006-02-15";
        d1 = df.parse(s);
        Emp p = new Emp("张三",25,"男",5000,d1);
        FileOutputStream fos = new FileOutputStream("src/Pointer/File/IO/emp.dat");
        ObjectOutputStream oot = new ObjectOutputStream(fos);
        oot.writeObject(p);

        FileInputStream fis = new FileInputStream("src/Pointer/File/IO/emp.dat");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Emp pp = (Emp) ois.readObject();
        System.out.println(pp);

    }

反序列化操作2

另外,当JVM反序列化对象时,能找到class⽂件,但是class⽂件在序列化对象之后发⽣了修改,那么反序列化操作也会失败,抛出⼀个 InvalidClassException InvalidClassException 异常。发⽣这个异常的原因如下:

  1. 该类的序列版本号与从流中读取的类描述符的版本号不匹配
  2. 该类包含未知数据类型
  3. 该类没有可访问的⽆参数构造⽅法
    Serializable 接⼝给需要序列化的类,提供了⼀个序列版本号。 serialVersionUID 该版本号的⽬的在于验证序列化的对象和对应类是否版本匹配。
public class Employee implements java.io.Serializable {
 // 加⼊序列版本号
 private static final long serialVersionUID = 1L;
 public String name;
 public String address;
 // 添加新的属性 ,重新编译, 可以反序列化,该属性赋为默认值.
 public int eid;
 public void addressCheck() {
 System.out.println("Address check : " + name + " -- " + address);
 }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值