Java基础 -----IO流

Java基础 -----IO流,第1张

Java基础 -----IO流

文章目录

1、File类

概述File类的实例化File类常用方法 2、IO流

2.1、概述

流的体系结构 2.2、节点流

FileReader、FileWriterFileInputStream、FileOutputStream 2.3、缓冲流2.4、转换流

编码集 2.5、标准输入、输出流2.6、打印流2.7、数据流2.8、对象

自定义类序列化 2.9、随机存取文件

1、File类 概述

java.io.File类:文件和文件目录路径的抽象表示形式,与平台无关File 能新建、删除、重命名文件和目录,但File 不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录。File对象可以作为参数传递给流的构造器File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹) File类的实例化

常用构造器

public File ( String pathname )

public  File ( String pathname )
//pathname为路径(相对路径或绝对路径)
//相对路径:相对于当前module(" test.txt ")
//绝对路径:相对于磁盘(“E:\java\test.txt ”)

//File类提供常量:public static final String separator(代替分隔符)
//绝对路径可以表示成:“E:” + file.separator + "java" + file.separator + "test.txt"

//路径分隔符:window = “\”    
//            Unix= " / "   

public File( String parent , String child)

以parent为父路径,child为子路径,创建File对象 public File( File parent , String child)

在parent文件或文件目录下创建child文件或文件目录 File类常用方法

获取功能

名称作用public String getAbsolutePath()获取绝对路径public String getPath()获取路径public String getName()获取名称public String getParent()获取上层文件目录路径。若无,返回nullpublic long length()获取文件长度(即:字节数)。不能获取目录的长度。public long lastModified()获取最后一次的修改时间,毫秒值 (+ new Date(毫秒数) 配套使用)public String[] list()获取指定目录下的所有文件或者文件目录的名称数组public File[] listFiles()获取指定目录下的所有文件或者文件目录的File数组

重命名

名称作用public boolean renameTo( File dest)将当前File对象的文本内容转移到dest中,然后当前File对象删除,dest名称不变

判断功能(一个File类对象只能是文件或文件目录其中一个,不能两者都是)

名称作用public boolean isDirectory()判断是否是文件目录public boolean isFile()判断是否是文件public boolean exists()判断是否存在public boolean canRead()判断是否可读public boolean canWrite()判断是否可写public boolean isHidden()判断是否隐藏

创建功能

名称作用public boolean createNewFile()创建文件。若文件存在,则不创建,返回falsepublic boolean mkdir()创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。public boolean mkdirs()创建文件目录。如果此文件目录存在,就不创建了。如果上层文件目录不存在,一并创建public boolean delete()删除文件或者文件目录(Java中的删除不走回收站)(删除对象必须是最底层) 2、IO流 2.1、概述

I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。Java程序中,对于数据的输入/输出 *** 作以“流(stream)”的方式进行。java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。

流的分类

按 *** 作数据单位不同分为:字节流(8 bit),字符流(16 bit)按数据流的流向不同分为:输入流,输出流按流的角色的不同分为:节点流,处理流 流的体系结构

2.2、节点流

节点流又称文件流对于文本文件(.txt,.java,.c,.cpp),使用字符流处理对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,…),使用字节流处理 FileReader、FileWriter

FileReader属于节点流、字符流、输入流FIleWriter属于节点流、字符流、输出流对于文本文件(.txt,.java,.c,.cpp),使用字符流处理

读入 *** 作

public void test1() {
        FileReader fr = null;

        try {
            //字符输入流
            
            //步骤一:FileReader的实例化,并在构造器传入File类对象
            fr = new FileReader(new File("E:\Javatest\test.txt"));

            
            //步骤二:读入 *** 作
            //方式一:
            int len;
            while ((len = fr.read()) != -1) { 
                //如果文件到达末尾,则返回 -1,否则返回文本字符
                System.out.print((char) len);
            }
            //read(构造器)
            //构造器有两种:1:空参      单个字符的赋值
            //              2: char[]  整串字符的赋值 


            //方式二:
            char[] arr = new char[5];

            fr.read(arr);

            while (fr.read(arr) != -1) {
                System.out.print(arr);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            
            //步骤三:资源的关闭,需另外try/catch
            try {
            if(fr != null)
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

读出 *** 作

        //字符输出流
        FileWriter fw = null;
        try {
            //步骤一:FileWriter的实例化,并在构造器传入File类对象
            fw = new FileWriter(new File("E:\Javatest\test1.txt"));

            
            //步骤二:数据的写入
            fw.write("ABCn");
            fw.write("123");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            
            //步骤三:资源的关闭
            try {
            if(fw != null)
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

通过节点流实现文本的复制

@Test

//将test.txt 复制到test2.txt
    public void test3() {
        FileReader fr = null;
        FileWriter fw = null;
        try {
            fr = new FileReader("E:\Javatest\test.txt");
            fw = new FileWriter("E:\Javatest\test2.txt");

            char[] arr = new char[5];
            int len;

            while ((len = fr.read(arr)) != -1) {
                fw.write(arr, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
            if(fr != null)
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
            if(fw != null)
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
FileInputStream、FileOutputStream

FileInputStream属于节点流、字节流、输入流FileOutStream属于节点流、字节流、输出流使用字节流FileInputStream处理文本文件,可能出现乱码。(文本文件可以用字节流实现复制等 *** 作,但是过要在java程序上输出就会出现乱码)对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,…),使用字节流处理

使用字节流实现图片的复制

package test7;

import org.testng.annotations.Test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FIleInputStreamOutputStream {
    @Test
    public void test1() {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream("E:\Javatest\photo\镁铝.jpg");
            fos = new FileOutputStream("E:\Javatest\photo\镁铝镁铝.jpg");

            int len;
            byte[] bytes = new byte[1024];

            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
            if(fis != null)
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
            if(fos != null)
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

2.3、缓冲流

缓存流是处理流的一种作用:提高文件的读写效率原因:为了提高数据读写的速度,Java API提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组,缺省使用8192个字节(8Kb)的缓冲区。

当读取数据时,数据按块读入缓冲区,其后的读 *** 作则直接访问缓冲区向流中写入字节时,不会直接写到文件,先写到缓冲区中直到缓冲区写满,BufferedOutputStream才会把缓冲区中的数据一次性写到文件里。使用方法flush()可以强制将缓冲区的内容全部写入输出流关闭流的顺序和打开流的顺序相反。只要关闭最外层流即可,关闭最外层流也会相应关闭内层节点流如果是带缓冲区的流对象的close()方法,不但会关闭流,还会在关闭流之前刷新缓冲区,关闭后不能再写出。 缓冲流要“套接”在相应的节点流之上,根据数据 *** 作单位可以把缓冲流分为:

BufferedInputStream和BufferedOutputStreamBufferedReader和BufferedWriter

处理流与节点流效率对比

package test7;

import org.testng.annotations.Test;

import java.io.*;

public class Buffered {
    @Test
    public void test1() {

        long start = System.currentTimeMillis();

        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            bis = new BufferedInputStream(new FileInputStream("E:\Javatest\photo\陈妍希.jpg"));
            bos = new BufferedOutputStream(new FileOutputStream("E:\Javatest\photo\陈妍希希.jpg"));

            int len;
            byte[] bytes = new byte[10];

            while ((len = bis.read(bytes)) != -1) {
                bos.write(bytes, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            try {
                if (bis != null)
                    bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (bos != null)
                    bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        long end = System.currentTimeMillis();

        System.out.println(end - start);//5

    }


    @Test
    public void test2() {
        long start = System.currentTimeMillis();

        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream("E:\Javatest\photo\陈妍希.jpg");
            fos = new FileOutputStream("E:\Javatest\photo\陈妍希希希.jpg");

            int len;
            byte[] bytes = new byte[10];

            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            try {
                if (fis != null)
                    fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                if (fos != null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        long end=System.currentTimeMillis();
        System.out.println(end-start); //177
    }
}

获取文本上字符出现的次数,把数据写入文件

package Problem;


import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

//获取文本上字符出现的次数,把数据写入文件
public class p12 {
    public static void main(String[] args) throws IOException {
        FileReader fr=new FileReader("E:\Javatest\test.txt");

        Map  map=new HashMap<>();

        int len;


        while((len=fr.read())!= -1){
            char cc=(char)len;

            if(map.containsKey(cc)){
                map.put(cc,map.get(cc)+1);//已经出现在集合中的元素
            }else{
                map.put(cc,1);//未出现在集合中的元素
            }
        }

        Set> entry=map.entrySet();

        for(Map.Entry en : entry){
            switch(en.getKey()){
                case ' ':
                    System.out.println("空格->"+en.getValue());
                    break;

                case 't':
                    System.out.println("tab键->"+en.getValue());
                    break;

                case 'n':
                    System.out.println("换行->"+en.getValue());
                    break;

                case 'r':
                    System.out.println("回车->"+en.getValue());
                    break;

                default:
                    System.out.println(en.getKey()+"->"+en.getValue());
        }
        }

    }

}

2.4、转换流

转换流是处理流的一种转换流提供了在字节流和字符流之间的转换很多时候我们使用转换流来处理文件乱码问题。实现编码和解码的功能。字节流中的数据都是字符时,转成字符流 *** 作更高效。Java API提供了两个转换流:

InputStreamReader:将InputStream转换为Reader

构造器:InputStreamReader(路径,编码类型) OutputStreamWriter:将Writer转换为OutputStream

构造器:OutputStreamWriter(路径,编码类型)

转换流实现文件的读入和写出

public class InputStreamReaderTest {
    
    @Test
    public void test2() throws IOException {
       
        File file1 = new File("dbcp.txt");
        File file2 = new File("dbcp_gbk.txt");

        FileInputStream fis = new FileInputStream(file1);
        FileOutputStream fos = new FileOutputStream(file2);

        InputStreamReader isr = new InputStreamReader(fis,"utf-8");
        OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");

        //2.读写过程
        char[] cbuf = new char[20];
        int len;
        while((len = isr.read(cbuf)) != -1){
            osw.write(cbuf,0,len);
        }

        //3.关闭资源
        isr.close();
        osw.close();
    }
}
编码集 名称概述ASCII美国标准信息交换码(用一个字节的7位可以表示)GB2312中国的中文编码表。最多两个字节编码所有字符GBK中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码Unicode国际标准码,融合了目前人类使用的所有字符。为每个字符分配唯一的字符码。所有的文字都用两个字节来表示。UTF-8变长的编码方式,可用1-4个字节来表示一个字符(修正后最多6个字节) 2.5、标准输入、输出流

System.in和System.out分别代表了系统标准的输入和输出设备默认输入设备是:键盘,输出设备是:显示器System.in的类型是InputStreamSystem.out的类型是PrintStream,其是OutputStream的子类FilterOutputStream的子类重定向:

public static void setIn(InputStream in)public static void setOut(PrintStream out)System类的setIn(InputStream is) / setOut(PrintStream ps)方式重新指定输入和输出的流。 2.6、打印流

实现将基本数据类型的数据格式转化为字符串输出打印流:PrintStream和PrintWriter

提供了一系列重载的print()和println()方法,用于多种数据类型的输出PrintStream和PrintWriter的输出不会抛出IOException异常System.out返回的是PrintStream的实例 2.7、数据流

用于读取或写出基本数据类型的变量或字符串数据流有两个类:

DataInputStreamDataOutputStream

将内存中的字符串、基本数据类型的变量写出到文件中。

public void test3() throws IOException {
        
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
        DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
        
        dos.writeUTF("ABC");
        dos.flush();//刷新 *** 作,将内存中的数据写入文件
        //writeXXX()一次,就得flush()一次
        dos.writeInt(23);
        dos.flush();
        dos.writeBoolean(true);
        dos.flush();

        //读取顺序与写入顺序一致
        String name = dis.readUTF();
        int age = dis.readInt();
        boolean isMale = dis.readBoolean();     
 
        System.out.println("name = " + name);
        System.out.println("age = " + age);
        System.out.println("isMale = " + isMale);   

        dos.close();
        dis.close();
    }

2.8、对象流

用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。序列化:用 ObjectOutputStream类 保存基本类型数据或对象的机制反序列化:用 ObjectInputStream类 读取基本类型数据或对象的机制ObjectOutputStream 和 ObjectInputStream 不能序列化 static 和 transient修饰的成员变量对象序列化机制:

允许把内存中的Java对象转化成与平台无关的二进制流,从而把二进制流持久地保存在磁盘中,或传输到另一个网络节点,其他程序也可以将此二进制流恢复成原来的Java对象 序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,使其在保存和传输时可被还原序列化过程:将内存中Java对象保存到磁盘或通过网络传输出去

package test7;

import org.testng.annotations.Test;

import java.io.*;

public class objectinputStream {
    @Test
    public void test() {

        ObjectOutputStream oos = null;
        try {

            oos = new ObjectOutputStream(new FileOutputStream("E:\Javatest\test.txt"));

            //write()一次 就得flush()一次
            oos.writeUTF("ABC");
            oos.flush();
            oos.writeDouble(1515.65);
            oos.flush();

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

        } finally {

            try {
                if (oos != null)
                    oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }

    @Test
    public void test4() {

        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("E:\Javatest\test.txt"));

            String s1 = ois.readUTF();
            double s2 = ois.readDouble();

            System.out.println(s1);
            System.out.println(s2);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (ois != null)
                    ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

自定义类序列化

自定义类需要满足

实现接口:Serializable(标识接口)、Externalizable之一当前类提供全局常量:serialVersionUID(作为一个标识符)

serialVersionUID:表明类的不同版本间的兼容性 自定义类内所有属性也必须为可序列化的(基本数据类型默认为可序列化)

序列化 *** 作

创建一个ObjectOutputStream调用ObjectOutputStream对象的writeObject(对象) 方法输出可序列化对象注意写出一次, *** 作flush()一次

反序列化 *** 作

创建一个ObjectInputStream对象调用readObject() 方法读取流中的对象

package test7;

import org.testng.annotations.Test;

import java.io.*;

public class persontest {
    @Test
    public void test() {
        ObjectOutputStream oos = null;
        try {
            Person p1 = new Person("Tom", 15);
            oos = new ObjectOutputStream(new FileOutputStream("E:\Javatest\person.txt"));

            oos.writeObject(p1);
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    @Test
    public void test1() {
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("E:\Javatest\person.txt"));

            Person p1 = (Person) ois.readObject();

            System.out.println(p1);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {

            try {
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

serialVersionUID的理解

凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:

public static final long serialVersionUIDserialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象进行版本控制,有关各版本反序列化时是否兼容。如果类没有显示定义这个静态常量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID可能发生变化。故建议,显式声明。 简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException) 2.9、随机存取文件流

RandomAccessFile 声明在java.io包下,但直接继承于java.lang.Object类。并且它实现了DataInput、DataOutput这两个接口,也就意味着这个类既是输出流,也是输入流。RandomAccessFile 类支持“随机访问” 的方式,程序可以直接跳到文件的任意地方来读、写文件RandomAccessFile 对象包含一个记录指针,用以标示当前读写处的位置。RandomAccessFile类对象可以自由移动记录指针:

long getFilePointer():获取文件记录指针的当前位置void seek(long pos):将文件记录指针定位到pos位置 构造器

public RandomAccessFile( File file, String mode )public RandomAccessFile( String name, String mode )mode参数指定访问模式r: 以只读方式打开

rw:打开以便读取和写入rwd:打开以便读取和写入;同步文件内容的更新rws:打开以便读取和写入;同步文件内容和元数据的更新 如果模式为只读r。则不会创建文件,而是会去读取一个已经存在的文件,如果读取的文件不存在则会出现异常。如果模式为rw读写。如果文件不存在则会去创建文件,如果存在则不会创建。

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

        RandomAccessFile raf1=new RandomAccessFile("E:\Javatest\photo\霸天虎.jpg","r");
        RandomAccessFile raf2=new RandomAccessFile("E:\Javatest\photo\霸天虎11.jpg","rw");

        int len;
        byte[] bytes=new byte[10];

        while((len=raf1.read(bytes))!= -1){
            raf2.write(bytes,0,len);
        }

        raf1.close();
        raf2.close();
    }

如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)

//读写 *** 作
 public void test3() throws IOException {
        RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");

        raf1.seek(3);//将指针调到角标为3的位置
        //保存指针3后面的所有数据到StringBuilder中
        StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
        byte[] buffer = new byte[20];
        int len;
        while((len = raf1.read(buffer)) != -1){
            builder.append(new String(buffer,0,len)) ;
        }
        //调回指针,写入“xyz”
        raf1.seek(3);
        raf1.write("xyz".getBytes());

        //将StringBuilder中的数据写入到文件中
        raf1.write(builder.toString().getBytes());

        raf1.close();
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5708674.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存