JavaSE--IO编程

Java IO编程

file类

File 类是唯一一个与文件本身操作(创建,删除,重命名等)有关的类,而如果想进行File 类的操作,必须要提供有完整的路径,才可以调用方法进行处理

File:抽象的描述了磁盘路径(创建一个具体的对象==>指定路径 但是该路径的文件或者文件夹不一定在磁盘真的存在!!!)。 一个File对象就是一个具体的文件或者目录(目的:指定文件或文件夹保存的路径)

File 类的基本使用

•构造方法:public File(String pathname),设置要操作完整路径; •构造方法:public File(File parent, String child),设置父路径与子目录 •构造方法:File(File parent, String child) 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。

•创建文件,返回值表示是否创建成功:public boolean createNewFile() throws IOException; ①当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件 ②如果路径不存在,就不能创建文件•判断文件是否存在:public boolean exists(); •删除文件:public boolean delete();boolean mkdir() :创建单级目录(文件夹),注意:如果父路径不存在,则不会创建文件夹 •boolean mkdirs() :创建多级目录,如果父路径不存在,会自动先创建路径所需的文件夹,即会先创建父路径内容再创建文件夹 •boolean isDirectory() :判断是否是一个目录 •boolean isFile() :判断是否是一个文件

•如何获取父路径:public File getParentFile()

public class FileDemo {
    public static void main(String[] args) throws Exception {
        String commonUrl = "D:" + File.separator + "JavaWorkSpace" + File.separator + "javabasic"+File.separator
                +"basic"+File.separator+"io"+File.separator+"file";
        File file = new File(commonUrl+File.separator+"test.txt");
        System.out.println(file);
        System.out.println("判断路径下文件是否存在:"+file.exists());//判断路径下文件是否存在

        System.out.println("判断file对象指向的路径是否是目录"+file.isDirectory());//判断file对象指向的路径是否是目录(在这里就是判断路径是否是文件夹.是就返回true)
        System.out.println("判断路径下的test.txt是否是文件类型"+file.isFile());//判断路径下的test.txt是否是文件类型
        //注意:文件所在路径(在这里的路径指:D:\JavaWorkSpace\javabasic\basic\io\file\)必须存在,才能创建文件(test.txt)
        System.out.println("创建文件: "+file.createNewFile());
        // 不存在的目录
        File file1 = new File(commonUrl+File.separator+"visual"+File.separator+"test"+File.separator+"test.txt");
        System.out.println("mkdir: "+file1.mkdir());//如果没有父路径,不会报错,但不会创建文件夹
        System.out.println("mkdirs: "+file1.mkdirs());//如果父路径不存在,会自动先创建路径所需的文件夹
    }
}
复制代码

自定义方法实现文件过滤

public class FileFilterDemo {
    public static void main(String[] args) {
        String path = "D:"+File.separator+"pictures"+File.separator+"nangong"+File.separator+"2022-06.07";
        File file = new File(path);
        String[] files = fileNameFilter(file);
        for (String s : files) {
            System.out.println("文件名: "+s);
        }
    }
    public static String[] fileNameFilter(File file){
        //2.保存1.指定父路径下所有的 文件和目录 的路径 到list中
        String[] list = file.list();
        //3.声明一个泛型数组list2用于保存所要查找的文件
        ArrayList<String> arrayList = new ArrayList<>();
        for (String s : list) {
            if(s.endsWith("jpg")){
                arrayList.add(s);
            }
        }
        String[] array =arrayList.toArray(new String[arrayList.size()]);
        return array;
    }
}
复制代码

获取文件信息

文件是否可读: public boolean canRead();

文件是否可写: public boolean canWrite();

获取文件长度: public long length(),该方法返回的是一个 long 数据类型。返回字节长度;(主要描述日期、时间、内存大小等)

最后一次修改日期时间: public long lastModified();

判断是否是目录: public boolean isDirectory();

判断是否是文件: public boolean isFile()

列出目录内容: public File[] listFiles

File删除文件和文件夹方法

/**
 * File删除文件和文件夹方法:
 *  1.删除文件:存在文件则直接删除返回true,如果不存在返回false
 *  2.删除目录:
 *    ①:为空:直接删除
 *    ②:不为空:删不掉 (需要先删除文件夹里面所有文件,再删除文件夹)
 *    ③:不存在直接返回false
 * 注意:delete方法 ==》直接从磁盘中删除,不能像回收站一样可以恢复!!
 * @Author luo
 * @Date 2022/8/7 - 21:32
 */
public class DeleteFileDemo {
    public static void main(String[] args) {
        String path = "D:"+File.separator+"pictures"+File.separator+"nangong"+File.separator+"2022-06.07";
        File file = new File(path);
        String[] files = fileNameFilter(file);
        for (String s : files) {
            System.out.println("文件名: "+s);
        }
    }
    /*
     * 如果是文件 ==》直接删除
     * 如果是目录 ==》必须先删除里面每一层目录里的所有文件,最后才能删除外层的目录
     *              原因:不为空的话 删不了
     */
    public static void deleteFile(File file) {
        if(file.exists()){
            //boolean isFile():测试此抽象路径名表示的文件是否是一个标准文件。
            if(file.isFile()){
                file.delete();
            }else {
                //保存 路径D:/1/新建文件夹2  下的所有的文件和文件夹到listFiles数组中
                //listFiles方法:返回file路径下所有文件和文件夹的绝对路径
                File[] files = file.listFiles();
                for (File file1 : files) {
                    /*
                     * 递归作用:由外到内先一层一层删除里面的文件 再从最内层 反过来删除文件夹
                     *    注意:此时的文件夹在上一步的操作之后,里面的文件内容已全部删除
                     *         所以每一层的文件夹都是空的  ==》最后就可以直接删除了
                     */
                    deleteFile(file1);
                }
            }
        } else{
            System.out.println("该file路径不存在!!");
        }
    }
    public static String[] fileNameFilter(File file){
        //2.保存1.指定父路径下所有的 文件和目录 的路径 到list中
        String[] list = file.list();
        //3.声明一个泛型数组list2用于保存所要查找的文件
        ArrayList<String> arrayList = new ArrayList<>();
        for (String s : list) {
            if(s.endsWith("jpg")){
                arrayList.add(s);
            }
        }
        String[] array =arrayList.toArray(new String[arrayList.size()]);
        return array;
    }
}
复制代码

File的list方法

static File[] listRoots() : 列出可用的文件系统根 ==>即列出计算机磁盘的盘符
String[] list() : 返回一个字符串数组,这些字符串指定file路径下的所有文件和目录 ==》列出文件名 File[] listFiles() : 返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件 ==》列出文件的绝对路径

System.out.println("列出计算机磁盘的盘符:");
File[] listRoots = File.listRoots();
for (File listRoot : listRoots) {
    System.out.println(listRoot);
}

System.out.println("\n列出路径下的所有文件和文件夹:");
File file2 = new File(commonUrl);
String[] list = file2.list();
for (String s : list) {
    System.out.println(s);
}

System.out.println("\n列出路径下的所有文件和文件夹的绝对路径:");
File[] files = file2.listFiles();
for (File file3 : files) {
    System.out.println(file3);
}
复制代码

字节流与字符流

IO 操作的核心意义在于:输入与输出操作,对于服务器或者是客户端而言,输入输出实质上传递的就是一种数据流(字节数据)的处理形式 字节处理流:OutputStream(输出字节流)、InputStream(输入字节流) 字符处理流:Writer(输出字符流)、Reduce(输入字符流)

文件处理的流程

  1. 进行文件的读写操作,首先一定要通过 File 类找到文件路径;

  2. 通过字节流或字符流的子类为父类对象实例化;

  3. 利用字节流或字符流中的方法实现数据的输入与输出操作;

  4. 流的操作属于资源操作,资源操作必须进行关闭处理

OutputStream字节输出流

字节的数据是以 byte 类型为主实现的操作,在进行字节内容输出的时候可以使用 OutputStream 类完成

实现了两个接口Closeable、Flushable

OutputStream 类是一个抽象类,而这个抽象类要获得实例化对象,应该通过子类实例向上转型完成, 例如FileOutputStream

No 方法名称 类型
01 public abstract void write(int b) throws IOException ; 普通 输出单个字节数据
02 public void write(byte[] b) throws IOException 普通 输出一组字节数据
03 public void write(byte[] b, int off, int len) throwsIOException 普通 输出部分字节数据

FileOutputStream类

FileOutputStream:文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。文件是否可用或能否可以被创建取决于基础平台。特别是某些平台一次只允许一个 FileOutputStream(或其他文件写入对象)打开文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。

FileOutputStream 用于写入诸如图像数据之类的原始字节的流。要写入字符流,一般使用 FileWriter。

public class ByteSteamDemo {
    public static void main(String[] args) throws IOException {
        String commonUrl = "D:" + File.separator + "JavaWorkSpace" + File.separator + "javabasic"+File.separator
                +"basic"+File.separator+"io"+File.separator+"steam";
        File file = new File(commonUrl+"test.txt");
        if(!file.getParentFile().exists()){
            //文件不存在,创建目录
            file.getParentFile().mkdirs();
        }
        try(OutputStream fileOutputStream = new FileOutputStream(file, true)){
            String str = "\r\n字节输出流\r\n";
            //方式①:写入一个字节 void write(int b) : 将指定字节写入此文件输出流。
            fileOutputStream.write(97);//写入的是:a

            //方式②:写入文字  void write(byte[] b) :将 b.length 个字节从指定 byte 数组写入此文件输出流中。
            fileOutputStream.write(str.getBytes());
            //方式③:写入指定字节          void write(byte[] b, int off, int len) :将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
            byte[] b = new byte[] {97,98,99,65,66,67};
            fileOutputStream.write(b, 0, 4);//写入从b数组起始位置为0 开始 的4个字节    (在这里写入的即是:abcA)

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

    }
}

复制代码

InputStream 字节输入流

InputStream 类主要实现的就字节数据读取

No 方法名称 类型
01 public abstract int read) throws IOException 普通 读取单个字节数据,如果现在已经读取到底了,返回-1
02 public int read(byte[] b) throws IOException 普通 的个数,如果没有数据读取,已经读取到底了,则返回-1
03 public int read(byte[] b, int off, int len) throws IOException 普通 读取一组字节数据,只占数组的部分

FileInputStream类

FileInputStream :用于读取诸如图像数据之类的原始字节流。要读取字符流,一般使用 FileReader

try(FileInputStream fileInputStream = new FileInputStream(file)){
    byte data[] = new byte[1024];
    int len = fileInputStream.read(data);
    System.out.println(new String(data,0,len));
}catch (IOException e){
    e.printStackTrace();
}
复制代码

Writer 字符输出流

直接利用字符串完成

输出字符数组: public void write(char[] cbuf) throws IOException;

输出字符串: public void write( String str) throws IOException;

Reader 字符输入流

没有像 Writer 类一样提供有整个字符串的输入处理操作,只能够利用字符数组来接收

public class CharSteamDemo {
    public static void main(String[] args) throws IOException {
        String commonUrl = "D:" + File.separator + "JavaWorkSpace" + File.separator + "javabasic"+File.separator
            +"basic"+File.separator+"io"+File.separator+"steam";
        /**
         *
         * 注意: ①:要刷新或者关闭流才能将数据写入到文件中!!
         *         ②:关闭流的时候会自动刷新流
         *       ③:关闭流之后不能再使用流!
         */
        File file = new File(commonUrl + "charSteamTest.txt");
        if(!file.getParentFile().exists()){
            //文件不存在,创建目录
            file.getParentFile().mkdirs();
        }
        FileWriter fileWriter = new FileWriter(file);
        fileWriter.write(25);
        fileWriter.flush();//刷新流
        fileWriter.write("字符流输出");
        fileWriter.close();
        FileReader reader = new FileReader(file);
        int read = reader.read();
        //方式①:public int read():读取单个字符。
//        while (read != -1){
//            System.out.println((char) read);
//            read = reader.read();
//        }
        // 方式②:将字符读入数组中的某一部分。
        char[] c = new char[10];
        int len;
        while ((len = reader.read(c)) != -1){
            System.out.println(new String(c, 0, len));
        }
        reader.close();
    }
}
复制代码

操作的单位不一样,一个是字节[byte-8bit],一个是字符[变长字节] 操作中文的时候使用字符流更方便 ,字节流更广泛:文本,视频,音频,图片... 字符流中有可以直接写字符串的方法 字节输出流 : 程序 ---> 磁盘文件 , 如果不关闭流也会写入

IO流中字节流和字符流的区别

字符输出流 : 程序 ==> 缓冲【flush/close】 ==> 磁盘文件 如果不关闭流或者刷新缓冲区,不会写入文件 字符输出流 关闭的时候会先刷新,关闭之后不能够在操作,刷新之后可以继续操作 写入的数据比较多时, 则可以在中途手动调用刷新的方法提交数据

IO流读写乱码问题(字符编码)

1.编码 : String ---> byte[] String中有对应的方法:byte[] getBytes() : 使用平台的默认字符集将此 String 编码为 byte 序列

2.解码 : byte[] ---> String String中有对应的构造方法:

字符编码

ASCII编码:用来表示英文,它使用1个字节表示,其中第一位规定为0,其他7位存储数据,一共可以表示128个字符。 0-7数据 : 英文的编码 GBK ==》 ASCII ex: 65 ==》A 97 ==》a 拓展ASCII编码:用于表示更多的欧洲文字,用8个位存储数据,一共可以表示256个字符 GBK/GB2312/GB18030:简称国标,表示汉字。GB2312表示简体中文,GBK/GB18030表示繁体中文 Unicode编码:包含世界上所有的字符,是一个字符集, 缺点就是大。 UTF-8:编码象形文字部分使用16进制编码,而普通的字母采用的是 ISO8859-1 编码 ISO8859-1:是单字节编码,国际通用编码,向下兼容ASCII,不支持中文!

	//编码
	byte[] b = "这个数据是中文!可能会出现乱码".getBytes();
	System.out.println(Arrays.toString(b));
	byte[] b2 = "这个数据是中文!可能会出现乱码".getBytes("UTF-8");
	System.out.println(Arrays.toString(b2));
	
	//解码:
	System.out.println(new String(b));
	System.out.println(new String(b, "utf-8"));//编码和解码规则不一致 ==》出现乱码问题
	System.out.println(new String(b2,"GBK"));//编码和解码规则不一致 ==》出现乱码问题
	System.out.println(new String(b2,"utf-8"));//编码和解码规则一致 ==》不会出现乱码问题
复制代码

转换流

实现字节流与字符流操作的功能转换

OutputStreamWriter:字符输出流转字节输出流

InputStreamReader:字节输入流转字符输入流

转换的本质在于对象的转型和构造方法的接收。通过类的继承结构与构造方法,可以发现转换处理就是将接收到的字节流对象通过向上转流型变为字符流对象

public class TransFormDemo {
    public static void main(String[] args) throws IOException {
        String commonUrl = "D:" + File.separator + "JavaWorkSpace" + File.separator + "javabasic"+File.separator
                +"basic"+File.separator+"io"+File.separator+"steam";
        File file = new File(commonUrl+"test.txt");
        if(!file.getParentFile().exists()){
            //文件不存在,创建目录
            file.getParentFile().mkdirs();
        }
        try(OutputStream fileOutputStream = new FileOutputStream(file, true)){
            String str = "\r\n转换流\r\n";
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
            outputStreamWriter.write(str);
            outputStreamWriter.flush();
        }catch (IOException e){
            e.printStackTrace();
        }

        try(FileInputStream fileInputStream = new FileInputStream(file)){
            char data[] = new char[1024];
            InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
            int len = inputStreamReader.read(data);
            System.out.println(new String(data,0,len));
        }catch (IOException e){
            e.printStackTrace();
        }

    }
}
复制代码

文件拷贝

public class FileCopy {
    public static void main(String[] args) throws Exception {
        if(args.length != 2) {
            System.out.println("初始化参数出错");
            System.exit(1);
        }
        long start = System.currentTimeMillis();
        FileUtil fileUtil = new FileUtil(new File(args[0]), new File(args[1]));
        if(new File(args[0]).isFile()){
            System.out.println(fileUtil.copy() ? "文件拷贝成功" : "文件拷贝失败");
        }else{
            System.out.println(fileUtil.copyDir() ? "文件拷贝成功" : "文件拷贝失败");
        }
        long end = System.currentTimeMillis();
        System.out.println("用时:" +(end-start));
    }
}

class FileUtil{
    private File sourceFile;
    private File targetFile;

    public FileUtil(File sourceFile, File targetFile) {
        this.sourceFile = sourceFile;
        this.targetFile = targetFile;
    }

    public boolean copy() throws IOException {
        if(!this.sourceFile.exists()){
            System.out.println("拷贝源文件不存在");
            return false;
        }
        if(!this.targetFile.getParentFile().exists()){
            this.targetFile.getParentFile().mkdirs();
        }
        return this.copyFileImpl(this.sourceFile, this.targetFile);
    }

    public boolean copyDir() throws Exception{
        try {
            this.copyImpl(this.sourceFile);
            return true;
        }catch (Exception e){
            return false;
        }
    }
    private void copyImpl(File file) throws Exception {
        if(!targetFile.getParentFile().exists()){
            targetFile.getParentFile().mkdirs();
        }
        if(file.isDirectory()){
            File[] listFiles = file.listFiles();
            if(listFiles != null){
                for (File listFile : listFiles) {
                    copyImpl(listFile);
                }
            }
        }else{
            System.out.println(file.getPath().replace(this.sourceFile.getPath() + File.separator, ""));
            String newFilePath = file.getPath().replace(this.sourceFile.getPath() + File.separator, "");
            File newFile = new File(this.targetFile, newFilePath);
            this.copyFileImpl(file, newFile);
        }
    }
    private boolean copyFileImpl(File sourceFile, File targetFile) throws IOException {
        byte[] bytes = new byte[1024];
        InputStream input = null;
        OutputStream output = null;
        try {
            input = new FileInputStream(sourceFile);
            output = new FileOutputStream(targetFile);
            int len = 0;
            while((len = input.read(bytes)) != -1){
                //拷贝的内容都在data数组
                output.write(bytes, 0, len);
            }
//            input.transferTo(output);
            return true ;
        }catch (Exception e){
            throw e;
        } finally {
            if(input!=null){
                input.close();
            }
            if(output != null){
                output.close();
            }
        }
    }
}
复制代码

内存操作流

文件流都是程序利用 InputStream 读取文件内容,而后程序利用 OutputStream 向文件输出内容,所有的操作都是以文件为终端的。

内存流实现 IO 操作,可是又不产生文件(相当于临时文件),以内存为终端进行处理

void close():关闭 内存流 无效。 之前的IO流都是跟磁盘文件建立了连接,需要关闭连接即关闭流! 而关闭内存流跟连接无关

  • ByteArrayInputStream :包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。
  • ByteArrayOutputStream : 此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。
  • CharArrayReader: 此类实现一个可用作字符输入流的字符缓冲区。
  • CharArrayWriter:此类实现一个可用作 Writer 的字符缓冲区。缓冲区会随向流中写入数据而自动增长。可使用 toCharArray() 和 toString() 获取数据。
public class ByteAarraySteamDemo {
    public static void main(String[] args) throws IOException {
        String str = "nangong";
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(str.getBytes());
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        int data = 0;
        while ((data = byteArrayInputStream.read()) != -1){
            byteArrayOutputStream.write(Character.toUpperCase((char) data));
        }
        System.out.println(byteArrayOutputStream);
        System.out.println( byteArrayOutputStream.toByteArray());
        System.out.println(byteArrayOutputStream.toString());
        byteArrayInputStream.close();
        byteArrayOutputStream.close();


        //内存字符流============================================================================
        CharArrayWriter caw = new CharArrayWriter();
        caw.write("这是内存字符流写入的内容");

        char[] ch = caw.toCharArray();

        //使用内存输入流 读取获得内存中的保存数据的数组
        CharArrayReader car = new CharArrayReader(ch);

        //读
        int len2;
        char[] c = new char[10];
        while((len2 = car.read(c)) != -1){
            System.out.print(new String(c,0,len2));
        }
        
    }
}
复制代码

管道流

实现两个线程之间的 IO 处理操作

· 字节管道流:PipedOutputStream、PipedInputStream;

连接处理:public void connect(PipedInputStream snk)throws IOException;

· 字符管道流:PipedWriter、PipedReader。

连接处理:public void connect(PipedReader snk)throws IOException

注意资源关闭

public class PipeDemo {
    public static void main(String[] args) throws IOException {
        SendThread send = new SendThread();
        ReceiveThread receive = new ReceiveThread();
        send.getOutput().connect(receive.getInput());
        new Thread(send,"消息发送线程: ").start();
        new Thread(receive,"消息接收线程: ").start();
    }
}

class SendThread implements Runnable{
    private PipedOutputStream pipedOutputStream;// 管道输出流
    @Override
    public void run() {
        try {
            int i = 0;
            this.pipedOutputStream.write(("第"+(i+1)+"次信息发送").getBytes());
            this.pipedOutputStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    public SendThread() {
        this.pipedOutputStream = new PipedOutputStream();
    }
    public PipedOutputStream getOutput(){
        return pipedOutputStream;
    }
}
class ReceiveThread implements Runnable{
    private PipedInputStream pipedInputStream;
    @Override
    public void run() {
        int i = 0;
        int len = 0;
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte bytes[] = new byte[1024];
        try {
            while ((len = this.pipedInputStream.read(bytes)) != -1){
                byteArrayOutputStream.write(bytes, 0, len);
            }
            System.out.println(Thread.currentThread().getName()+"接收信息"+new String(byteArrayOutputStream.toByteArray()));
            byteArrayOutputStream.close();
            this.pipedInputStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("第"+i+1+"次信息发送");

    }
    public ReceiveThread(){
        this.pipedInputStream = new PipedInputStream();
    }
    public PipedInputStream getInput(){
        return pipedInputStream;
    }
}
复制代码

RandomAccessFile类

RandomAccessFile : 此类的实例支持对随机访问文件的读取和写入 随机访问文件RandomAccessFile:网络传输的时候 ,断点续传(传入一半,网络断了,接着上一个位置继续数据的传输写入

  1. * long getFilePointer():获得偏移量
  2. * void seek(long pos):设置文件指针
  3. * long length():返回此文件的长度
  4. * void setLength(long newLength):设置此文件的长度
public class RandomAccessFileDemo {
    public static void main(String[] args) throws IOException {
        String commonUrl = "D:" + File.separator + "JavaWorkSpace" + File.separator + "javabasic"+File.separator
                +"basic"+File.separator+"io"+File.separator+"steam";
        File file = new File(commonUrl+"RandomAccessFile.txt");
        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
        String names[] = {"jujinyi ", "reba    ", "yangzi  "};
        int ages[] = new int[] {26, 28, 27};
        for (int i = 0; i< names.length; i++) {
            randomAccessFile.write(names[i].getBytes());
            randomAccessFile.writeInt(ages[i]);
        }

        System.out.println(randomAccessFile.getFilePointer());//32   表示该文件偏移量是32,从0开始的,从第0个字节开始
        //随机读写文件好处:断点续传,传入一半,网络断了,接着上一个位置继续数据的传输写入
        randomAccessFile.setLength(1024*1024);//1024byte=1KB   1024*1024=1M
        //setLength可以做上传下载【下载视频  ==》磁盘占用存储空间】

        randomAccessFile.close();
        File file1 = new File(commonUrl+"RandomAccessFile.txt");
        RandomAccessFile randomAccessFile1 = new RandomAccessFile(file1, "rw");
        {
            randomAccessFile1.skipBytes(24);
            byte[] bytes = new byte[8];
            int len = randomAccessFile1.read(bytes);
            System.out.println("姓名:"+new String(bytes,0,len).trim()+", 年龄:"+ randomAccessFile1.readInt());
        }
        {
            randomAccessFile1.seek(12);//设置指针位置12 ==> 即设置的偏移量12
            byte[] bytes = new byte[8];
            int len = randomAccessFile1.read(bytes);//即将第12个字节处开始
            System.out.println("姓名:"+new String(bytes,0,len).trim()+", 年龄:"+ randomAccessFile1.readInt());
        }
        {
            randomAccessFile1.seek(0);
            byte[] bytes = new byte[8];
            int len = randomAccessFile1.read(bytes);
            System.out.println("姓名:"+new String(bytes,0,len).trim()+", 年龄:"+ randomAccessFile1.readInt());
            randomAccessFile1.close();
        }
    }
}
复制代码

输入与输出

OutputStream 类必须要转为字节数组后才可以输出

解决OutputStream 类问题 =>打印流: PrintStream、 PrintWriter。

打印流

PrintStream:字节打印流 PrintWriter:字符打印流

JDK 1.5 PrintWriter 类追加有格式化输出: ``public PrintWriter printf (String format,0bject , args)

public class PrintWriterDemo {
    public static void main(String[] args) throws FileNotFoundException {
        String commonUrl = "D:" + File.separator + "JavaWorkSpace" + File.separator + "javabasic"+File.separator
                +"basic"+File.separator+"io"+File.separator+"steam";
        PrintStream ps = new PrintStream(commonUrl+"PrintStream.txt");
        ps.println("这是写入文件的内容");
        ps.close();
        PrintWriter pw = new PrintWriter(commonUrl+"PrintWriter.txt");
        String name = "nangong";
        int age = 26;
        pw.printf("姓名: %s, 年龄: %d", name, age);
        pw.print("收入:" + 78.00);
        pw.close();
    }
}
复制代码

标准输入输出流以及标准错误输出流

System.out 是一个特殊的 PrintStream "标准"输出流 ==》 输出结果到控制台 System.err 是一个特殊的 PrintStream "标准"错误输出流 ==》输出到控制台 System.in 是一个特殊的InputStream "标准"输入流 ==》 接收数据源到控制台输入

修改 out 的输出位置: public static void setOut( PrintStream out); 修改 err 的输出位置: public static void setErr( PrintStreamerr)。

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

        System.out.println("标准输出流:输出到指定的输出流  ==》 输出到控制台");
        //1.
        PrintStream out = System.out;
        out.println("标准输出流对象调用输出方法");

        //2.
        PrintStream err = System.err;
        err.println("标准错误输出流  ==》 输出到控制台");

        //3.
        InputStream in = System.in;
        int len;
        byte[] b  = new byte[1024];
        //nio非阻塞式IO流
        //此处: 因为in流持续在,检测后台的数据,只要有了就能读取出来,没有就在该处阻塞
        while((len = in.read(b)) != -1){//阻塞了执行流程: 阻塞式IO流
            System.out.println(new String(b,0,len));
        }
    }
}
复制代码

BufferedReader类

BufferedReader 类提供的是一个缓冲字符输入流的概念,利用 BufferedReader 类可以很好的解决输入流数据的读取问题

缓冲流:在读取的过程中,对其他的IO流进行一个包装:以达到高效的读写操作, 磁盘 <---->(缓冲) <----> 内存

读取一行数据: public String readLine() throws IOException; 。

  • BufferedInputStream:为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 reset 方法的能力
  • BufferedOutputStream:该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。
  • BufferedReader:从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
  • BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
public class BufferReaderDemo {
    public static void main(String[] args) throws IOException {
        BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入");
        String str = input.readLine();
        System.out.println(str);
        String video = "D:" + File.separator + "JavaWorkSpace" + File.separator + "javabasic"+File.separator
                +"basic"+File.separator+"io"+File.separator;
        long start = System.nanoTime();//纳秒  ==》目的:测试读写效率
        FileInputStream fis = new FileInputStream(video+"theme.mp4");
        int len;
        byte[] b = new byte[1024];
        while((len = fis.read(b)) != -1){
            //System.out.println(new String(b,0,len));
        }
        long end = System.nanoTime();//纳秒
        System.out.println(end-start);

        //注意:测试时   读取的次数  读取文件的数据量   自己创建的字节数组大小也很关键
        //BufferedInputStream:
        long start2 = System.nanoTime();//纳秒
        BufferedInputStream bis = new BufferedInputStream(fis);
        int len2;
        byte[] b2 = new byte[1024];
        while((len2 = bis.read(b2)) != -1){
            //System.out.println(new String(b2,0,len2));
        }
        long end2 = System.nanoTime();//纳秒
        System.out.println(end2-start2);//会发现缓冲流读写效率更高

        //BufferedReader:
        BufferedReader br = new BufferedReader(new FileReader(video+"theme.mp4"));
        System.out.println(br.readLine());//String readLine() : 读取一个文本行。 如果已到达流末尾,则返回 null
        String line = null;
        while((line = br.readLine()) != null){
            System.out.println(line);
        }

        //BufferedWriter:
        BufferedWriter bw = new BufferedWriter(new FileWriter(video+"theme.txt"));
        bw.write("这是要写入的内容!!!");
        bw.newLine();//newLine() :写入一个行分隔符。   ==》即换行
        bw.write("这是要写入的内容!!!");
        bw.flush();//字符流需要刷新   ==》意味着没有关闭,关闭是关闭与磁盘文件的连接

    }
}
复制代码

Scanner扫描流

JDK 1.5 追加的一个程序类,为了解决输入流的访问问题, BufferedReader 的替代功能类 Scanner implments Iterator[ hasNext Next]: 一个Scanner 可以通过迭代的方式,将一个文本的数据,全部迭代出来

枸造: public Scanner InputStream source): 判断是否有数据: public boolean hasNext(): 取出数据: public String next(); 设置分隔符: public Scanner useDelimiter(String pattern)

对象序列化

序列化:类实现Serializable接口,然后添加版本号

序列化与反序列化

对象流:将对象永久保存到磁盘或者进行网络传输 (注意:前提是对象能够序列化,然后提供一个版本号)

ObjectInputStream : 从文件中读取出保存的对象 ObjectOutputStream :从内存中、代码中 将对象写入磁盘文件 【能够将对象永久的保存到磁盘文件中】

public class SerializableDemo{
    private static final String COMMONURL = "D:" + File.separator + "JavaWorkSpace" + File.separator + "javabasic"+File.separator
            +"basic"+File.separator+"io"+File.separator+"src"+File.separator+"Serializable.txt";
    private static final File FILE = new File(SerializableDemo.COMMONURL);

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Student stu = new Student("nangong", 26);
//        PrintStream ps = new PrintStream(COMMONURL);
//        ps.print(stu);
        //   stu.toString仅仅打印的是字符串 不是对象

//        serialObject(stu);
        System.out.println(unSerialObject());
    }
    public static void serialObject(Object obj) throws IOException {
        // 序列化
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE));
        oos.writeObject(obj);
        oos.close();
    }
    public static Object unSerialObject() throws IOException, ClassNotFoundException {
        // 反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE));
        Object obj = ois.readObject();
        ois.close();
        return obj;
    }
}
class Student implements Serializable {
    //序列化ID实在序列化之后 反序列化 ==》转换成当前对象 比较类型的时候  不仅比较类型 而且还会比较序列化ID
    private static final long serialVersionUID = 1L;//给该类对象添加版本号
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString(){
        return name+"-->"+age;
    }
}
复制代码

Transient 关键字

解决部分属性序列化的问题

进行序列化处理,加上transient关键字的属性是不会被保存下来的,对应的默认值”null”

public class SerializableDemo{
    private static final String COMMONURL = "D:" + File.separator + "JavaWorkSpace" + File.separator + "javabasic"+File.separator
            +"basic"+File.separator+"io"+File.separator+"src"+File.separator+"Serializable.txt";
    private static final File FILE = new File(SerializableDemo.COMMONURL);

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Student stu = new Student("nangong", 26);
//        PrintStream ps = new PrintStream(COMMONURL);
//        ps.print(stu);
        //   stu.toString仅仅打印的是字符串 不是对象

        serialObject(stu);
        System.out.println(unSerialObject());
    }
    public static void serialObject(Object obj) throws IOException {
        // 序列化
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE));
        oos.writeObject(obj);
        oos.close();
    }
    public static Object unSerialObject() throws IOException, ClassNotFoundException {
        // 反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE));
        Object obj = ois.readObject();
        ois.close();
        return obj;
    }
}
class Student implements Serializable {
    //序列化ID实在序列化之后 反序列化 ==》转换成当前对象 比较类型的时候  不仅比较类型 而且还会比较序列化ID
    private static final long serialVersionUID = 1L;//给该类对象添加版本号
    private transient String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString(){
        return name+"-->"+age;
    }
}
复制代码

image.png

猜你喜欢

转载自juejin.im/post/7130269114643251214