• 第九章 IO流技术


    1.IO是什么意思? data source是什么意思?


    IO:Input Output;
    data source:数据源。


    2.字节流和字符流有什么区别?输入流和输出流有什么区别?


    字符流和字节流是流的一种划分,按照处理流的数据单位进行的划分。两类都分为输入和输出操作。在字节流中输出数据主要是使用OutputStream完成,输入使用的是InputStream,在字符流中输出主要是使用Writer类完成,输入流主要使用Reader类完成。这四个都是抽象类。字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。字节流是最基本的,所有的InputStrem和OutputStream的子类都是字节流,主要用在处理二进制数据,它是按字节来处理的。但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的编码来处理,也就是要进行字符集的转化,这两个之间通过 InputStreamReader,OutputStreamWriter(转换流)来关联,实际上是通过byte[]和String来关联的。

    流就像管道一样,在程序和文件之间,输入输出的方向是针对程序而言,向程序中读入东西,就是输入流,从程序中向外读东西,就是输出流。输入流是得到数据,输出流是输出数据。

    3.节点流和处理流有什么区别?


    节点流和处理流是流的另一种划分,按照功能不同进行的划分。节点流,可以从或向一个特定的地方(节点)读写数据。处理流是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。

    4.word文档能使用字符流操作吗?为什么?


    不能。因为word文档不是纯文本文件,除了文字还包含很多格式信息。不能用字符流操作。可以用字节流操作。
    305.【上机】完成老师课堂上读入文件数据的代码:
    static void testReader(){
    File f = new File("d:/a.txt");
    FileInputStream fis = null;
    try {
    fis = new FileInputStream(f);
    int m = 0;
    while((m=fis.read())!=-1){
    char c = (char) m;
    System.out.print(c);
    }
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }finally{
    try {
    if(fis!=null){
    fis.close();
    }
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }

    5.解释下面代码的含义:


    通过上例得知fis是字节输入流对象,fis.read()是每次从指定文件读取一个字节,返回值是这个字节所代表的int类型的整数。如果读到文件结尾(没有内容可读了),那么返回-1。

    下面的代码是依次读取文件,每次一个字节,循环读取;每次读完后将返回的整数值(m)转成char类型的数据(强转)(从而知道每次读取的是什么字符),输出这个字符。直到读完为止。

    while((m=fis.read())!=-1){
    char c = (char) m;
    System.out.print(c);
    }

    6.流对象使用完后,一般要调用close方法关闭,释放资源。 这种做法对吗?


    对。


    7.【上机】完成老师写文件的操作:


    static void testWrite(){
    FileOutputStream fos = null;
    String str = "sffsdfsdfsdfsdfsdfsdfsdf";
    try {
    fos = new FileOutputStream("d:/b.txt");
    /*for(int i=0;i<str.length();i++){
    fos.write(str.charAt(i));
    }*/
    fos.write(str.getBytes());

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

    8.InputStream和OutputStream基本特点是?


    二者都是【字节】输入输出流的抽象父类。以字节为单位处理数据,每次读取/写入一个字节。适合处理二进制文件,如音频、视频、图片等。实现类有FileInputStream和FileOutputStream等。


    9.Reader和Writer的基本特点是?


    二者都是【字符】输入输出流的抽象父类。以字符为单位处理数据,每次读取/写入一个字符。适合处理文本文件。实现类有FileReader和FileWriter等。

    10.FileInputStream和FileOutputStream的基本作用是?


    二者都是【字节】输入输出流的实现类,其抽象父类是InputStream和OutputStream。以字节为单位处理数据,每次向/从指定文件读取/写入一个字节。适合处理二进制文件,如音频、视频、图片等。


    11.FileReader和FileWriter的作用是?


    二者都是【字符】输入输出流的实现类,其抽象父类是Reader和Writer。以字符为单位处理数据,每次向/从指定文件读取/写入一个字符。适合处理文本文件。


    12.【上机】完成文件的copy代码


    思路:先把源文件读到程序里,在从程序写到目标文件。
    代码示例:
    //1.创建数据源文件;
    File file=new File("e:\picture1.jpg");
    //2.搭建输入流管道;
    InputStream is=new FileInputStream(file);
    //3.创建目的地文件;
    File file1=new File("e:\picture2.jpg");
    //4.搭建输出流管道;
    OutputStream os=new FileOutputStream(file1);
    int b=0;
    //每次从源文件读出一个字节(b=is.read()),就向目标文件写入一个字节
    //(os.write(b));
    while((b=is.read())!=-1){
    os.write(b);
    }
    //读写全部完成后关闭资源;
    os.close();
    is.close();
    }

    13.BufferInputStream和BufferedOutputStream的特点是?


    BufferInputStream和BufferedOutputStream分别是【缓冲】字节输入输出流,还有【缓冲】字符输入输出流(BufferReader和BufferedWriter)。
    缓冲流是处理流,它不直接连接数据源/目的地,而是以一个节点流为参数,在节点流的基础上,提供一些简单操作。

    先说不带缓冲的流的工作原理吧:它读取到一个字节/字符,就向用户指定的路径写出去,读一个写一个,所以就慢了。带缓冲的流的工作原理:读取到一个字节/字符,先不输出,等凑足了缓冲的最大容量后一次性写出去,从而提高了工作效率
    优点:减少对硬盘的读取次数,降低对硬盘的损耗。

    14.【上机】使用BufferedReader和BufferedWriter实现文本文件的拷贝。


    //第一部分:准备从文件读数据到程序;
    Reader reader=new FileReader(new File("e:\a.txt"));//创建读取对象reader;
    BufferedReader br=new BufferedReader(reader); //创建缓冲流包装reader;
    //第二部分:准备从程序写到文件;
    Writer writer=new FileWriter(new File("e:\a3.txt"));//创建写入对象writer;

    BufferedWriter bw=new BufferedWriter(writer);//创建缓冲流包装writer;
    String str=null;
    //用循环边读(str=br.readLine())边写(bw.write(str));
    while((str=br.readLine())!=null){
    bw.write(str);
    bw.newLine();
    }
    bw.flush();//清空缓冲区;
    //copy完成后关闭资源;
    bw.close();
    br.close();
    }


    15.InputStreamReader和OutputStreamWriter的作用是?


    二者都是转换流,从字节流转换为字符流,是包装流,以一个节点流为参数;提供一些方便读写【字符】的方法。

    代码示例(InputStreamReader):
    publicstaticvoid main(String[] args) throws IOException {
    //1.节点流;
    InputStream is=new FileInputStream(new File("e:\a1.txt"));
    //2.处理流:把字节流转换成了字符流;
    InputStreamReader isr=new InputStreamReader(is,"utf-8");
    int temp=0;

    //用转换流对象isr进行读取操作,以字符(而不是字节)为单位读取文本文件,方便操//作。
    while((temp=isr.read())!=-1){
    System.out.print((char)temp);
    }
    isr.close();
    }

    OutputStreamWriter(略).


    16.PrintStream打印流经常用于什么情况? System.out 是不是打印流?


    PrintStream:字节打印流,是OutputStream的实现类。提供了多个重载的print,println等方法,可以方便地向文本文件中写入数据。
    System.out是字节打印流(PrintStream的对象),它被称作标准的输出流,输出的目的地是标准的输出设备,即显示器。所以,当我们使用System.out.print或System.out.println时会向屏幕(显示器)输出数据。

    PrintStream的继承关系:


    17.【上机】实现字节数组和任何基本类型和引用类型执行的相互转换。


    提示:使用ByteArrayInutStream和ByteArrayOutputStream。
    1.字节数组和基本数据类型之间的转换,以boolean类型为例:
    (1)输出一个boolean类型的数据:

    boolean flag=true;//先定义一个boolean类型的变量;

    ByteArrayOutputStream baos=new ByteArrayOutputStream();
    DataOutputStream dos=new DataOututStream(baos);
    dos.writeBoolean(flag);

    byte[] b=baos.toByteArray();
    //接下来可以把byte数组构建成一个数据包(DatagramPacket)发送出去;
    (2)读取一个boolean类型的数据:
    byte[] b=new byte[1024];
    //我们已接收到包含一个boolean类型数据的数据包(代码略);数据信息已经包含在byte数组b里,接下来就把boolean类型的数据读出来并保持原类型;

    ByteArrayInputStream bais=new ByteArrayInputStream(b);
    DataInputStream dis=new DataInputStream(bais);
    boolean flag=dis.readBoolean();//这样数据就读出来了并保持着原来的数据类型。
    2.字节数组和引用类型之间的转换:
    (1)输出一个引用类型信息:
    //先建一个类,如User(代码略);

    User user=new User();
    ByteArrayOutputStream baos=new ByteArrayOutputStream();
    ObjectOutputStream oos=new ObjectOutputStream(baos);
    oos.writeObject(user);

    byte[] b=baos.toByteArray();
    //接下来可以把byte数组构建成一个数据包(DatagramPacket)发送出去;

    (2)读取一个引用类型信息:
    byte[] b=new byte[1024];
    //我们已接收到包含一个User类型数据的数据包(代码略);
    //数据信息已经包含在byte数组b里,接下来就把User类型的数据读出来并保持原类型;

    ByteArrayInputStream bais=new ByteArrayInputStream(b);
    ObjectInputStream ois=new ObjectInputStream(bais);
    User user=(User)ois.readObject();//这样数据就读出来了并保持着原来的数据类型。

    18.DataInputStream和DataOutputStream的特点是?


    二者都是处理流,要以一个节点流为参数;二者被称为数据流,是用来操作基本数据类型的。用DataInputStream写入一个类型的数据,用DataOutputStream读出数据时可以保持类型不变。如用DataInputStream写入一个int类型的数据,用DataOutputStream读出来的还是一个int数据,即可以直接当作int类型的数据来进行操作,不用做任何转换。

    代码示例:
    publicclass TestDataInputStream {
    publicstaticvoid main(String[] args) throws IOException {
    //1.写数据;
    OutputStream os=new FileOutputStream(new File("e:\f.data"));//构建节点流;
    DataOutputStream dos=new DataOutputStream(os);//用数据流包装节点流;
    int n=123456;
    String str="尚学堂教育";
    dos.writeInt(n);//用数据流写入一个int类型的数值(n是int类型的);
    dos.writeUTF(str); //用数据流写入一个String类型的数据;
    dos.writeDouble(3.15); //用数据流写入一个double类型的数据;
    dos.writeChar('我'); //用数据流写入一个char类型的数据;
    dos.writeBoolean(true); //用数据流写入一个布尔类型的数据;
    //2.读数据;
    InputStream is=new FileInputStream(new File("e:\f.data"));
    DataInputStream dis=new DataInputStream(is);
    int n1=dis.readInt();//用数据流读出刚才写入的int类型数据,赋给int类型变量;
    String str1=dis.readUTF();//用数据流读出String类型的数据;
    double d=dis.readDouble();//用数据流读出double类型的数据;
    char c=dis.readChar();//用数据流读出char类型的数据;
    boolean flag=dis.readBoolean();//用数据流读出布尔类型的数据;


    //打印输出用数据流读出来的数据;
    System.out.println(n1);
    System.out.println(str1);
    System.out.println(d);
    System.out.println(c);
    System.out.println(flag);
    //关闭资源;
    dis.close();
    dos.close();
    }
    }

    结果:
    123456
    尚学堂教育
    3.15

    true

    数据流特点:
    (1)写入是什么类型的数据,读出是相应类型的数据;
    (2)要先写后读;用DataOutputStream流写,用DataInputStream流读;
    (3)读写顺序要一致,否则会报EOF异常;EOF:end of file;
    (4)数据流可以跨平台写入和读出,适合网路应用。

    19.【上机】使用ObjectInputstream和ObjectOutputStream实现将某个对象存 储到硬盘上,然后再读到程序中。


    见课堂实例。


    20.中文乱码是怎么造成的?


    字符流的读写根据需要设置编码方式,编码方式设置不当会出现中文乱码。

    21.unicode字符集是几个字节表示一个字符?为什么需要utf-8?


    Unicode字符集中2个字节表示一个字符。


    22.序列化和反序列化指的是什么?


    (1) 序列化:
    将对象以byte流的形式写入到文件中->序列化;
    将要被序列化的对象的类要实现Serializable接口:
    publicclassUserimplements Serializable {
    //略;
    }
    User实现了这个接口,代表User这个类的对象具有了将对象以byte流的形式写进文件的功能。

    (2) 反序列化:
    将文件中的数据以byte流的形式读到程序中来,依然是一个对象反序列化。

    23.想序列化某个类的对象,该类必须实现sierializable接口吗?


    要序化的对象必须实现Serializable接口,以启动序列化的功能。


    24.说说sierializable接口的特点。


    1. 需要被序列化的对象的类必须实现Serializable接口。
    2. 给类加个序列化编号,即给类定义一个标记,如:
    public static final long serialVersionUID=1L;
    新的修改后的类还可以操作曾经序列化的对象。
    3、静态是不能被序列化的,
    序列化只能对堆中的对象进行序列化 ,不能对”方法区”中的对象进行序列化。
    4、不需要序列化的字段前加 transient,如:
    private transient String password;

    25.transient的作用是?


    不希望序列化的属性,可以添加transient关键字;
    密码字段是非常敏感的字段,所在在序列化时,不允许写到文件:
    private transient String password;


    26.【上机】完成目录的copy代码(结合递归算法)


    import java.io.*;
    /**
    * CopyDocJob定义了实际执行的任务,即
    * 从源目录拷贝文件到目标目录
    */
    public class CopyDir2 {
    public static void main(String[] args) {
    try {
    copyDirectiory("d:/301sxt","d:/301sxt2");
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    /**
    * 复制单个文件
    * @param sourceFile 源文件
    * @param targetFile 目标文件
    * @throws IOException
    */
    private static void copyFile(File sourceFile, File targetFile) throws IOException {
    BufferedInputStream inBuff = null;
    BufferedOutputStream outBuff = null;
    try {
    // 新建文件输入流
    inBuff = new BufferedInputStream(new FileInputStream(sourceFile));
    // 新建文件输出流
    outBuff=new BufferedOutputStream(new FileOutputStream(targetFile));
    // 缓冲数组
    byte[] b = new byte[1024 * 5];
    int len;
    while ((len = inBuff.read(b)) != -1) {
    outBuff.write(b, 0, len);
    }
    // 刷新此缓冲的输出流
    outBuff.flush();
    } finally {
    // 关闭流
    if (inBuff != null)
    inBuff.close();
    if (outBuff != null)
    outBuff.close();
    }
    }

    /**
    * 复制目录
    * @param sourceDir 源目录
    * @param targetDir 目标目录
    * @throws IOException
    */
    private static void copyDirectiory(String sourceDir, String targetDir) throws IOException {
    // 检查源目录
    File fSourceDir = new File(sourceDir);
    if(!fSourceDir.exists() || !fSourceDir.isDirectory()){
    return;
    }
    //检查目标目录,如不存在则创建
    File fTargetDir = new File(targetDir);
    if(!fTargetDir.exists()){
    fTargetDir.mkdirs();
    }
    // 遍历源目录下的文件或目录
    File[] file = fSourceDir.listFiles();
    for (int i = 0; i < file.length; i++) {
    if (file[i].isFile()) {
    // 源文件
    File sourceFile = file[i];
    // 目标文件
    File targetFile = new File(fTargetDir, file[i].getName());
    copyFile(sourceFile, targetFile);
    }
    //递归复制子目录
    if (file[i].isDirectory()) {
    // 准备复制的源文件夹
    String subSourceDir = sourceDir + File.separator + file[i].getName();
    // 准备复制的目标文件夹
    String subTargetDir = targetDir + File.separator + file[i].getName();
    // 复制子目录
    copyDirectiory(subSourceDir, subTargetDir);
    }
    }
    }
    }

    27.【上机】假设从入学开始所有书写的Java代码都在d:/sxtjava文件夹下,包括多
    级子文件夹。使用IO流获取从入学开始,到目前为止已经写了多少行Java代码。


    提示:获取d:/sxtjava文件夹及其子文件夹下的所有.java文件,使用readLine()读取其中每一行,每读取一行,行数加1。
    public class TestCountDir {
    private int count;
    /**
    * 统计一个java文件的行数
    */
    private void countLine(File sourceFile) throws IOException {
    BufferedReader br = null;
    try {
    // 新建文件输入流
    br = new BufferedReader(new FileReader(sourceFile));
    while(br.readLine()!=null){
    count++;
    //System.out.println(count);
    }
    } finally {
    br.close();
    }
    }
    /**
    * 统计一个目录下所有Java文件的行数
    */
    private void countDir(String sourceDir) throws IOException {
    // 检查源目录
    File fSourceDir = new File(sourceDir);
    if(!fSourceDir.exists() || !fSourceDir.isDirectory()){
    System.out.println("源目录不存在");
    return;
    }
    // 遍历目录下的文件或目录
    File[] file = fSourceDir.listFiles();
    for (int i = 0; i < file.length; i++) {
    if (file[i].isFile()) {
    if(file[i].getName().toLowerCase().endsWith(".java")){
    // System.out.println(file[i].getName());
    countLine(file[i]);
    }
    }
    //递归统计代码行数
    if (file[i].isDirectory()) {
    // 准备统计的文件夹
    String subSourceDir = sourceDir + File.separator + file[i].getName();
    // 统计子目录
    countDir(subSourceDir);
    }
    }
    }
    public static void main(String[] args) throws IOException {

    TestCountDir tcd = new TestCountDir();
    tcd.countDir("d:/sxtjava");
    System.out.println(tcd.count);
    }
    }


    28.【上机】下载并自学apache commons中的IO工具包。

  • 相关阅读:
    ado.net(增删改)
    窗体基础WINFORM
    SQL函数类的操作,增加,查询
    SQL数据库,增加查询修改以及防sql写入攻击
    SQL数据库--数据访问
    单列模式
    SQL数据库基础————委托
    SQL数据库基础知识——抽象类
    SQL数据库——静态成员
    面向对象
  • 原文地址:https://www.cnblogs.com/ren549047861/p/11294137.html
Copyright © 2020-2023  润新知