首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java入门(14)-- I/O(输入/输出)

Java入门(14)-- I/O(输入/输出)

作者头像
爱学习的程序媛
发布2022-04-07 15:39:18
发布2022-04-07 15:39:18
78700
代码可运行
举报
文章被收录于专栏:学习/读书笔记学习/读书笔记
运行总次数:0
代码可运行

在变量、数组和对象中存储的数据是暂时存在的,程序结束后它们就会丢失。想要永久地存储程序创建的数据,需要将其保存在磁盘文件中,这样就可以在其他程序中使用它们。Java中的I/O技术可以将数据保存到文本文件、二进制文件甚至是ZIP压缩文件中,以达到永久性保存数据的要求。

14.1 流概述

流是一组有序的数据序列,根据操作的类型,可分为流入流和流出流。I/O(Input/Output,输入/输出)流提供了一条通道程序,可以使用这条通道把源中的字节序列送到目的地。

输入模式:

输出模式:

14.2 输入/输出流

Java语言定义了许多类专门负责各种方式的输入/输出,这些类都被放在java.io包中。其中,所有输入流类都是抽象类InputStream(字节输入流)或抽象类Reader(字符输入流)的子类;所有输出流都是抽象类OutputStream(字节输出流)或抽象类Writer(字符输出流)的子类。

14.2.1 输入流

InputStream类是字节输入流的抽象类,是所有字节输入流的父类。

InputStream类的层次结构:

该类中所有方法遇到错误时都会引发IOException异类,该类中的一些方法:

read():从输入流中读取数据的下一个字节,返回0~255范围内的int字节值,如果已经到达流末尾而没有可用的字节,则返回值为-1;

read(byte[] b):从输入流中读入一定长度的字节,并以整数的形式返回字节数;

mark(int readlimit):在输入流的当前位置放置一个标记,readlimit参数告知此输入流在标记位置失效之前允许读取的字节数;

reset():将输入指针返回到当前所做的标记处;

skip(long n):跳过输入流上的n个字节并返回实际跳出的字节数;

markSupported():如果当前流支持mark()/reset()操作就返回true;

close():关闭此输入流并释放与该流关联的所有系统资源。

注:并不是所有的InputStream类的子类都支持InputStream中定义的所有方法,如skip()、mark()、reset()等方法只对某些子类有用。

Java中的字符是Unicode编码,是双字节的,InputStream是用来处理字节的,并不适合处理字符文本。Java为字符文本的输入专门提供了一套单独的类Reader,Reader类是字符输入流的抽象类,所有字符输入流的实现都是它的子类。

14.2.2 输出流

OutputStream类是字节输出流是抽象类,此抽象类是表示输出字节流的所有类的超类。

OutputStream类的层次结构:

OutputStream类中的所有方法均返回void,在遇到错误时会引发IOException异常,该类中的一些方法:

write(int b):将指定的字节写入此输出流;

write(byte[] b):将b个字节从指定的byte数组写入此输出流;

write(byte[] b, int off, int len):将指定byte数组中从偏移量off开始的len个字节写入此输出流;

flush():彻底完成输出并清空缓存区;

close():关闭输出流。

Writer类是字符输出流的抽象类,所有字节输出类的实现都是它的子类。

Writer类的层次结构:

14.3 File类

File类是java.io包中唯一代表磁盘文件本身的对象,File类定义了一些与平台无关的方法来操作文件,可以通过调用File类中的方法,实现创建、删除、重命名文件等操作。File类的对象主要用来获取文件本身的一些信息,如文件所在的目录、文件的长度、文件读写权限等,数据流可以将数据写入到文件中,文件也是数据流最常用的数据媒体。

14.3.1 文件的创建与删除

3种创建文件对象的构造方法:

File(String pathname):通过将给定路径名字符串转换为抽象路径名创建

File(String parent, String child):根据定义的父路径和子路径字符串(包含文件名)创建

File(File f, String child):根据parent抽象路径名和child路径名字符串创建

代码语言:javascript
代码运行次数:0
运行
复制
package core;
import java.io.*;
public class FileTest {
  public static void main(String[] args) {
    File file = new File("word.txt");
    if(file.exists()) {
      file.delete();
      System.out.println("文件已删除");
    } else {
      try {
        file.createNewFile();//创建文件
        File f = file.getAbsoluteFile();//获取文件的绝对路径
        System.out.println("文件已创建" + f);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}
14.3.2 获取文件信息

File类的常用方法:

代码语言:javascript
代码运行次数:0
运行
复制
package core;
import java.io.*;
public class FileTest1 {
  public static void main(String[] args) {
    File file = new File("word.txt");
    if(file.exists()) {
      String name = file.getName();
      long length = file.length();
      boolean hidden = file.isHidden();
      System.out.println("文件名称:" + name);
      System.out.println("文件长度是:" + length);
      System.out.println("该文件是隐藏文件吗?:" + hidden);
    } else {
      System.out.println("该文件不存在");
    }
  }
}

运行结果:

14.4 文件输入/输出流
14.4.1 FileInputStream与FileOutputStream类

FileInputStream类与FileOutputStream类都用来操作磁盘文件,如果用户的文件读取需求比较简单,可以使用FileInputStream类,该类继承自InputStream。FileOutputStream类与FileInputStream类对应,提供了基本的文件写入能力,是OutputStream类的子类。

FileInputStream类常用的构造方法:

FileInputStream(String name)

FileInputStream(File file)

代码语言:javascript
代码运行次数:0
运行
复制
package core;
import java.io.*;
public class FileTest2 {
  public static void main(String[] args) {
    File file = new File("word.txt");
    try {
      FileOutputStream out = new FileOutputStream(file);
      byte buy[] = "今天天气好晴朗,处处好风光!".getBytes();
      out.write(buy);//将数组中的信息写入到文件中
      out.close();//关闭流
    } catch (Exception e) {
      e.printStackTrace();
    }
    try {
      FileInputStream in = new FileInputStream(file);
      byte byt[] = new byte[1024];
      int len = in.read(byt);
      System.out.println("文件中的信息是:" + new String(byt, 0 ,len));//输出文件中的信息
      in.close();//关闭流
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

注:创建一个FileOutputStream对象时,可以指定不存在的文件名,但此文件不能是一个已经被其他程序打开的文件。

14.4.2 FileReader和FileWriter类

使用FileOutputStream类向文件中写入数据与使用FileInputStream类从文件中将内容读出来,都存在一点不足,即这两个类都指提供了对字节或字节数组的读取方法。由于汉字在文件中占用两个字节,如果使用字节流,读取不好可能会出现乱码现象,此时采用字符流Reader或Writer类即可避免这种现象。

FileReader和FileWriter字符流对应了FileInputStream和FileOutputStream类。FileReader流顺序地读取文件,只要不关闭流,每次调用read()方法就顺序地读取源中其余的内容,直到源的末尾或流被关闭。

代码语言:javascript
代码运行次数:0
运行
复制
package core;
import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Ftest extends JFrame{
  private static final long serialVersionUID = 1L;
  private JPanel jContentPane = null;//创建面板对象
  private JTextArea jTextAtea = null;//创建文本域对象
  private JPanel controlPanel = null;//创建面板对象
  private JButton openButton = null;//创建按钮对象
  private JButton closeButton = null;//创建按钮对象
  private JButton getOpenButton () {
    if (openButton == null) {
      openButton = new JButton();
      openButton.setText("写入文件");
      openButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          File file = new File("word.txt");
          try {
            FileWriter out = new FileWriter(file);
            String s = jTextAtea.getText();
            out.write(s);
            out.close();
          } catch (Exception e1) {
            e1.printStackTrace();
          }
        }
      });
    }
    return openButton;
  }
  private JButton getCloseButton() {
    if(closeButton == null) {
      closeButton = new JButton();
      closeButton.setText("读取文件");
      closeButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          File file = new File("word.txt");
          try {
            FileReader in = new FileReader(file);
            char byt[] = new char[1024];
            int len = in.read(byt);
            jTextAtea.setText(new String(byt, 0, len));
            in.close();
          } catch (Exception e1) {
            e1.printStackTrace();
          }
        }
      });
    }
    return closeButton;
  }
  private JTextArea getJTextAtea() {
    if(jTextAtea == null) {
      jTextAtea = new JTextArea();
    }
    return jTextAtea;
  }
  private JPanel getControlPanel() {
    if(controlPanel == null) {
      controlPanel = new JPanel();
      controlPanel.add(getOpenButton(),BorderLayout.WEST);
      controlPanel.add(getCloseButton(),BorderLayout.EAST);
    }
    return controlPanel;
  }
  public Ftest() {
    super();
    initialize();
  }
  private void initialize() {
    this.setSize(300,200);
    this.setContentPane(getJContentPane());
    this.setTitle("JFrame");
  }
  private JPanel getJContentPane() {
    if(jContentPane == null) {
      jContentPane = new JPanel();
      jContentPane.setLayout(new BorderLayout());
      jContentPane.add(getJTextAtea(),BorderLayout.CENTER);
      jContentPane.add(getControlPanel(),BorderLayout.SOUTH);
    }
    return jContentPane;
  }
  public static void main(String[] args) {
    Ftest  thisClass = new Ftest();
    thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    thisClass.setVisible(true);
  }
}

运行结果:

14.5 带缓存的输入/输出流

缓存是I/O的一种性能优化,缓存流为I/O流增加了内存缓存区,有了缓存区,使得在流上执行skip()、mark()、reset()方法成为可能。

14.5.1 BufferedInputStream与BufferedOutputStream类

BufferedInputStream类可以对所有InputStream类进行带缓存区的包装以达到性能的优化。

BufferedInputStream类有两种构造方法:

BufferedInputStream(InputSrteam in):创建了一个带有32个字节的缓存流

BufferedInputStream(InputStream in, int size):按指定的大小创建缓存区

BufferedInputStream读取文件过程:

使用BufferedOutputStream输出信息和用OutputStream输出信息完全一样,只不过BufferedOutputStream有一个flush()方法用来将缓存区的数据强制输出完。

BufferedOutputStream类有两个构造方法:

BufferedOutputStream(OutputStream in):创建一个有32个字节的缓存区

BufferedOutputStream(OutputStream in, int size):以指定的大小来创建缓存区

注:flush()方法用于即使在缓存区没有满的情况下,也将缓存区的内容强制写入到外设,习惯上称这个过程为刷新。flush()方法只对使用缓存区的OutputStream类的子类有效,当调用close()方法时,系统在关闭流之前,也会将缓存区中的信息刷新到磁盘文件中。

14.5.2 BufferedReader与BufferedWriter类

BufferedReader类与BufferedWriter类分别继承Reader类与Writer类,这两个类具有内部缓存机制,并可以以行为为单位进行输入/输出。

BufferedReader类读取文件的过程:

BufferedReader类常用的方法:

read():读写单个字符

readLine():读取一个文本行,并将其返回为字符串,如无数据可读,则返回null

BufferedWriter类常用的方法(都返回void):

write(String s, int off, int len):写入字符串的某一部分

flush():刷新该流的缓存

newLine():写入一个行分隔符

注:在使用BufferedWriter类的write()方法时,数据并没有立刻被写入输出流,而是首先进入缓存区中,如果想立刻将缓存区中的数据写入输出流,一定要调用flush()方法。

代码语言:javascript
代码运行次数:0
运行
复制
package core;
import java.io.*;
public class Student1 {
  public static void main(String[] args) {
    String content[] = {"好久不见", "最近好吗", "常联系"};
    File file = new File("word.txt");
    try {
      FileWriter fw = new FileWriter(file);
      BufferedWriter bufw = new BufferedWriter(fw);
      for (String c : content) {
        bufw.write(c);
        bufw.newLine();
      }
      bufw.close();
      fw.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
    try {
      FileReader fr = new FileReader(file);
      BufferedReader bufr = new BufferedReader(fr);
      String s = null;
      int i = 0;
      while((s = bufr.readLine()) != null) {
        i++;
        System.out.println("第" + i + "行:" + s);
      }
      bufr.close();
      fr.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

运行结果:

14.6 数据输入/输出流

数据输入/输出流(DataInputStream类与DataOutputStream类)允许应用程序以与机器无关的方式从底层输入流中读取基本Java数据类型,即当读取一个数据时,不必关心这个数值应当是哪种字节。

DataInputStream类与DataOutputStream类的构造方法:

DataInputStream(InputStream in):使用指定的基础的InputStream创建

DataOutputStream(OutputStream out):创建一个新的数据输出流,将数据写入指定基础输出流

DataOutputStream类提供了3种写入字符串的方法:

writeBytes(String s):将字符串中的每一个字符的低字节内容写入目标设备中

writeChars(String s):将字符串中的每一个字符的两个字节的内容都都写到目标设备中

writeUTF(String s):将字符串按照UTF编码后的字节长度写入目标设备,然后是每一个字节的UTF编码

DataInputStream类的方法:

readUTF():返回字符串

代码语言:javascript
代码运行次数:0
运行
复制
package core;
import java.io.*;
public class Example {
  public static void main(String[] args) {
    try {
      FileOutputStream fs = new FileOutputStream("word.txt");
      DataOutputStream ds = new DataOutputStream(fs);
      ds.writeUTF("使用writeUTF()方法写入数据;");
      ds.writeChars("使用writeChars()方法写入数据;");
      ds.writeBytes("使用writeBytes()方法写入数据;");
      ds.close();
      FileInputStream fis = new FileInputStream("word.txt");
      DataInputStream dis = new DataInputStream(fis);
      System.out.println(dis.readUTF());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
14.7 ZIP压缩输入/输出流
14.7.1 压缩文件

利用ZipOutputStream类对象可将文件压缩为.zip文件。

ZipOutputStream类的构造方法:

ZipOutputStream(OutputStream out)

ZipOutputStream类的常用方法(返回值都为void):

putNextEntry(ZipEntry e):开始写一个新的ZipEntry,并将流内的位置移至此entry所指数据的开头

write(byte[] b, int off, int len):将字节数组写入当前ZIP条目数据

finish():完成写入ZIP输出流的内容,无须关闭它所配合的OutputStream

setComment(String comment):可设置此ZIP文件的注释文字

示例:压缩D盘根目录下的hello文件夹

代码语言:javascript
代码运行次数:0
运行
复制
package core;
import java.io.*;
import java.util.zip.*;
public class MyZip {
  private void zip(String zipFileName, File inputFile) throws Exception {
    ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFileName));
    zip(out, inputFile, "");
    System.out.println("压缩中...");
    out.close();
  }
  private void zip(ZipOutputStream out, File f, String base) throws Exception{
    if (f.isDirectory()) {
      File[] fl = f.listFiles();
      if (base.length() != 0) {
        out.putNextEntry(new ZipEntry(base + "/"));
      }
      for (int i = 0; i < fl.length; i++) {
        zip(out, fl[i], base + fl[i]);
      }
    } else {
      out.putNextEntry(new ZipEntry(base));
      FileInputStream in = new FileInputStream(f);
      int b;
      System.out.println(base);
      while ((b = in.read()) != -1) {
        out.write(b);
      }
      in.close();
    }
  }
  public static void main(String[] args) {
    MyZip book = new MyZip();
    try {
      book.zip("D:/hello.zip", new File("D:/hello"));
      System.out.println("压缩完成");
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
}

运行结果:

14.7.2 解压缩ZIP文件

ZipInputStream类可读取ZIP压缩格式的文件,包括已压缩和未压缩的条目(entry)。

ZipInputStream类的构造方法:

ZipInputStream(InputStream in)

ZipInputStream类的常用方法:

read(byte[] b, int off, int len):返回int值,读取目标b数组内off偏移量的位置,长度是len字节

available():返回int值,判断是否已读完目前entry所指定的数据,已读完返回0,否则返回1

closeEntry():返回void值,关闭当前ZIP条目并定位流以读取下一个条目

skip(long n):返回long值,跳过当前ZIP条目中指定的字节数

getNextEntry():返回ZipEntry,读取下一个ZipEntry,并将流内的位置移至该entry所指数据的开头

createZipEntry(String name):返回ZipEntry,以指定的name参数新建一个ZipEntry对象

代码语言:javascript
代码运行次数:0
运行
复制
package core;
import java.io.*;
import java.util.zip.*;
public class Decompressing {
  public static void main(String[] args) {
    File file = new File("D:\\hello.zip");
    ZipInputStream zin;
    try {
      ZipFile zipFile = new ZipFile(file);
      zin = new ZipInputStream(new FileInputStream(file));
      ZipEntry entry;
      while(((entry = zin.getNextEntry()) != null) && !entry.isDirectory()) {
        File tmp = new File(entry.getName());
        if(!tmp.exists()) {
          tmp.getParentFile().mkdirs();
          OutputStream os = new FileOutputStream(tmp);
          InputStream in = zipFile.getInputStream(entry);
          int count = 0;
          while((count = in.read()) != -1) {
            os.write(count);
          }
          os.close();
          in.close();
        }
        zin.closeEntry();
        System.out.println(entry.getName() + "解压成功");
      }
      zin.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

运行结果:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-05-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 爱学习的程序媛 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 14.1 流概述
  • 14.2 输入/输出流
    • 14.2.1 输入流
    • 14.2.2 输出流
  • 14.3 File类
    • 14.3.1 文件的创建与删除
    • 14.3.2 获取文件信息
  • 14.4 文件输入/输出流
    • 14.4.1 FileInputStream与FileOutputStream类
    • 14.4.2 FileReader和FileWriter类
  • 14.5 带缓存的输入/输出流
    • 14.5.1 BufferedInputStream与BufferedOutputStream类
    • 14.5.2 BufferedReader与BufferedWriter类
  • 14.6 数据输入/输出流
  • 14.7 ZIP压缩输入/输出流
    • 14.7.1 压缩文件
    • 14.7.2 解压缩ZIP文件
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档