IO输入输出流

IO输入输出流,第1张

I/O输入输出流

文章目录

I/O输入输出流

File类

构造方法

指定文件路径指定父目录路径和文件名指定父目录的对象和文件名指定URI统一资源标识符 常用方法

访问文件属性方法 *** 作方法 文件过滤器递归读取文件清理空文件夹 IO流

文件分类流的分类字节

InputStream

FileInputStreamByteArrayInputStream OutputStream

FileOutputStreamByteArrayOutputStream 文件复制序列化和反序列化

ObjectOutputStream 序列化 *** 作ObjectInputStream 反序列化 *** 作 缓冲字节流 字符流

文件输入输出流缓冲输入输出流

BufferedReader&BufferedWriter out&in 转换流

PrintWriter 随机读写流文件加密

I/O输入输出流 File类

java.io.file
表示电脑上的文件或者目录

无论是文件还是目录都通过File类表示提供了对文件和目录的基本 *** 作,如查看文件名,文件大小,新建或删除文件File不能访问文件的内容,需要I/O输入输出流访问文件的内容 构造方法 指定文件路径

File file = new File(path);

创建File文件时只是创建一个指向某个路径的对象,并不表示在硬盘中创建文件,这个路径指向的文件可以存在,也可以不存在。

绝对路径
以根路径开始的路径
关于路径分隔符(由于我的系统是Linux系统,故只说明Linux系统下的情况)
例:/home/Desktop/a.txt相对路径
不是以根开始的路径,相对于某个路径的路径,.表示当前目录,…表示上一级目录。相对路径的父目录默认的是项目根目录 指定父目录路径和文件名

File file = new File(father path, filepath);
指定父目录的对象和文件名
File file = new File(File fatherfile, filepath);
指定URI统一资源标识符

URL需要装换成URI使用

常用方法 访问文件属性方法 方法作用getParent()获取指定了文件的父目录length()文件大小,单位是字节lastModified()返回long时间戳canWrite()文件可读isFile()是否是普通文件isDirectory()是否是文件目录 *** 作方法 方法作用createNewFile()成功创建文件返回true,失败返回falserenameTo()文件重命名delete()返回是否删除成功mkdir()若父目录不存在会创建失败list()返回文件目录下所有文件和目录的名字,返回字符串数组File.separator返回 *** 作系统分隔符 文件过滤器

需要用到文件过滤的过滤器接口,重写过滤方法。例程如下:

public static void main(String[] args) {
        File file1 = new File("/data/JAVAProjects/Wangdao2022LF/File/src/com/file/test");
        //String[] list = file1.list();
        String[] list = file1.list(new FilenameFilter() {
            @Override
            public boolean accept(File file, String name) {
                return name.endsWith("png") || name.endsWith("gif") || name.endsWith("jpg");
            }
        });
        System.out.println(Arrays.toString(list));
    }
递归读取文件

在一般情况下,文件的路径有可能是一般文件,也有可能是文件目录,这时可以使用递归的思想,获取文件目录及其子目录下的所有文件。
代码实现如下:

public static void getFiles(File filePath){
        if(filePath.exists()){
            if(filePath.isFile()){
                System.out.println(filePath.getAbsolutePath());//如果目标文件是一
                //般文件,直接输出文件绝对路径
            }
            else{
                System.out.println(filePath.getAbsolutePath());//目标文件是目录
                //文件,直接输出目录绝对路径
                File[] files = filePath.listFiles();
                for(File f : files){
                    if(f.isFile())
                        System.out.println(f.getAbsolutePath());
                    else
                        getFiles(f);//此处使用递归,当子文件中含有目录的时候再次调
                        //用该函数,将子目录当成新的filePath参数,实现递归
                }
            }
        }
    }
清理空文件夹
public static void removeEmptyDirectory(File file){
        if(file.isDirectory()&& Objects.requireNonNull(file.listFiles()).length==0){
            file.delete();
            System.out.println("删除空目录" + file.getAbsolutePath());
            removeEmptyDirectory(file.getParentFile());
        }
        else if (file.isDirectory()){
            
            File[] files = file.listFiles();
            for(File f : files != null ? files : new File[0]){
                removeEmptyDirectory(f);
            }
        }
    }
IO流

可以理解成一组有顺序的、有起点有中点的动态数据集合
文件是数据在硬盘上的静态存储
流是传输时的动态形态

文件分类

文本文件
可以用记事本打开的文件,由字符组成二进制文件
除文本以外的文件都是二进制文件 流的分类

流的方向:
输入流:由InputStream,Reader作为父类
输出流:由OutputStream,Writer作为父类按流中数据的单位
字节流byte:由InputStream,OutputStream作为父类
字符流char:由Reader,Writer作为父类按数据的来源
节点流:直接对数据进行 *** 作
包装流:对一个节点流进行 *** 作 字节流 InputStream 方法作用FileInputStream以字节为单位,读取数据,返回一个int类型的值ByteArrayInputStream从字节中读取数据,将字节数组当做流输入的来源ObjectInputStream反序列化,通过从磁盘或网络获取的二进制文件中读取对象 FileInputStream

//JDK7中提供了一种新语法,叫try-with-source,能够自动关闭外部资源,无需手动关闭
        //此处只能创建对象,而且只能创建那些有实现了AutoClosable接口的对象
        try(FileInputStream fis = new FileInputStream("test.txt")){
            byte[] buffer = new byte[3];//buffer数组储存在文件缓冲区,而且不是实际内存而是JVM
            int num = fis.read(buffer);//减少对硬盘的读取次数,返回值是实际读取的字节数,如果读取到末尾返回的是-1
        }
        catch (IOException e){
            e.printStackTrace();
        }
ByteArrayInputStream

字节数组输入输出流 *** 作的是内存,不是外部设备因此无需关闭流

public static void byteArrayInputStream(){
        byte[] bytes = "hello world".getBytes();
        try{
            InputStream is = new ByteArrayInputStream(bytes);
            int i = -1;

            while((i = is.read())!= -1){
                System.out.println((char)i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
OutputStream 方法作用FileOutputStream以字节为单位,将文件写出到文件中ByteArrayOutputStream将数据写出到内置的字节数组中,即将字节数组当做输出的目的地ObjectOutputStream用于序列化,将对象写入二进制文件,以便通过磁盘或者网络传输 FileOutputStream
public static void main(String[] args) {
        FileOutputStream fos = null;
        
        try{
        //如果文件不存在,会自动创建文件;如果文件存在,则会覆盖重写,但是在构造时,能够使用重载的构造方法追加写入数据
            //fos = new FileOutputStream("test.txt");
            fos = new FileOutputStream("test.txt", true);
            byte[] data = "hello world".getBytes();
            fos.write(data);//只是把数据写入到缓冲区中
            fos.flush();//将缓冲区的数据刷新,写入到文件中,但是当关闭输出流时,会自动调用该方法
        }catch (IOException e){
            e.printStackTrace();
        }
    }
ByteArrayOutputStream
public static void byteArrayOutputStream(){
        OutputStream os = new ByteArrayOutputStream();
        try {
            os.write("hello,world".getBytes());
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(os);
    }
文件复制

每次复制一个字节,因为涉及到多次IO *** 作,传输时间更长

   int data = -1;
   while((data = is.read()) != -1){
   os.write(data);
            }
//488ms
//文件复制成功!

再看看多字节,我们一次复制1MB大小的字节数组

byte[] buffer = new byte[1024 * 1024];
int num = -1;
while((num = is.read(buffer))!=-1){
      os.write(buffer, 0, num);
}
//1ms
//文件复制成功!

时间就相差很大了。

序列化和反序列化

序列化:将Java对象写入到IO流中,实现将对象保存在磁盘上或者在网络中传递对象
反序列化:从IO流中读取Java对象,实现从磁盘和网络上恢复对象
要求:
对象必须实现Serializable接口才能序列化,转换成二进制流,通过网络进行传输

ObjectOutputStream 序列化 *** 作

ObjectOutputStream和ObjectInputStream都属于包装流

用于对节点流功能进行扩展创建包装流时,需要传入 *** 作的节点流对象关闭流时,只需要关闭包装流,节点流也会被关闭
ObjectOutputStream用于序列化,将对象写入二进制文件:

User user = new User(1001, "tom", 18);
        try {
            FileOutputStream fos = new FileOutputStream("user.data");//用来包装的流
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(user);
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
ObjectInputStream 反序列化 *** 作

注意事项:

对象必须实现Serializable接口,才能被序列化转换成二进制流通过网络传输;如果成员变量有对象属性,则对象属性也要序列化通过serialVersionUID用来判断序列化版本的一致性(反序列化时将流中携带的UID和本地相应实体的UID是否一致,才能进行反序列化)transient和static修饰的成员不会被序列化 缓冲字节流 字符流

Reader和Writer

文件输入输出流

/字符流不能 *** 作二进制文件,只能 *** 作文本文件

try (FileWriter writer = new FileWriter("noun.txt");
             FileReader reader = new FileReader("verb.txt")) {
            char[] buffer = new char[5];
            int num = -1;//每次读取一个字符,返回int类型的值,可以读汉字,不会出现乱码

            while ((num = reader.read(buffer)) != -1)
                writer.write(buffer, 0, num);
            System.out.println("文件复制成功");
            } catch (IOException e) {
            e.printStackTrace();
        }
缓冲输入输出流

缓冲输入输出流属于包装流,为字符添加缓冲的功能,当读取或者写出数据时,先放到缓冲区,再到缓冲区读取。

BufferedReader&BufferedWriter
try(
                BufferedReader reader = new BufferedReader(new FileReader("test.txt"));
                BufferedWriter writer = new BufferedWriter(new FileWriter("verb.txt"))
        )
        {
            String data;//每次读一行,读不到数据返回null
            while((data = reader.readLine()) != null)
                writer.write(data);
            System.out.println("复制成功");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
out&in

System.out :标准输入输出流,默认为显示器
System.in :标准输入流,默认为键盘

转换流

只能由字节流转换成字符流,同时可以实现编码的转换

PrintWriter

打印流,可以直接打印输出;’可以只以文件名作为参数

随机读写流

随机读写流是一个字节流,可以定义到任意的文件位置进行读写 *** 作,使用该流既能读取文件又能写入文件。

System.out.println(raf.getFilePointer());
            raf.seek(3);//使指针移动到指定位置
            raf.skipBytes(2);//指针往后跳过多少个字节,不能反着走
            System.out.println((char)raf.read());
文件加密

思想:将文件里的字节与int类型密码异或得到加密后的字符存到密码,然后对密码文件的每个字节和密码进行异或即可还原原来数据。

public static void secret(String filePath, int password) {
        String newFilePath, notice;
        if(filePath.endsWith(".sec"))
        {
            newFilePath = filePath.substring(0, filePath.length() - 4);
            notice = "解密完成!";
        }
        else {
            newFilePath = filePath + ".sec";
            notice = "加密完成!";
        }
        try(
                FileInputStream fis = new FileInputStream(filePath);
                FileOutputStream fos = new FileOutputStream(newFilePath);
                ) {
            int data = -1;
            while((data = fis.read()) != -1){
                fos.write(data ^ password);
            }

            System.out.println(notice);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        secret("test.txt.sec", 9527);
    }

加密后,由于生成的是二进制文件,显示出来是乱码:
߈�ф�ѯ�ߵ�߬�ߦ�ޏ�

解密后显示正常:
这波是肉蛋葱鸡

I/O部分到这里就结束了~

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

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

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

发表评论

登录后才能评论

评论列表(0条)

保存