IO流

File

  • File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)
  • File类声明在java.io包下
  • File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,并未涉及到写入或读取文件内容的操作。
    如果需要读取或写入文件内容,必须使用IO流来完成。
        //new File("hi.txt")构造器,硬盘上并没有创建hi.txt,只是在内存中操作的
        File file = new File("hi.txt");  //相对路径,idea中相对于当前工程
        System.out.println(file.getAbsoluteFile()); // E:\CodeMgr\GitWorkplace\Java\hi.txt

        try {
            boolean newFile = file.createNewFile(); //这句才是在磁盘中创建文件
        } catch (IOException e) {
            e.printStackTrace();
        }

Files

  • 静态的Files.1ist方法会返回一个可以读取目录中各个项的stream<Path>对象
public static void test2(){
        File file = new File("E:\\homework\\大四实训");
        Path path = file.toPath();
        try {
            Stream<Path> list = Files.list(path);
            list.map(m -> m).forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
  
}
/**result:
E:\homework\大四实训\大四实训
E:\homework\大四实训\大四实训2
*/
  • 1ist方法不会进入子目录。为了处理目录中的所有子目录,需要使用File.walk方法。
public static void test2(){
        File file = new File("E:\\homework\\大四实训");
        Path path = file.toPath();
        try {
            Stream<Path> walk = Files.walk(path, FileVisitOption.FOLLOW_LINKS);
            walk.map(m -> m).forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
  
}
/**result
E:\homework\大四实训
E:\homework\大四实训\大四实训
E:\homework\大四实训\大四实训\1234 abv 实训报告.doc
E:\homework\大四实训\大四实训\1234abv .pptx
E:\homework\大四实训\大四实训\java提升用到的工具软件
....
....
*/

流分类

注解:我们是站在程序(内存)的角度来 区分 流的流向,流向内存的叫输入流,流向文件的叫输出流

  • 按操作数据单位不同分为:字节流(8bit),字符流(16bit)
  • 按数据流的流向不同分为:输入流,输出流
  • 按流的角色不同分为:节点流(文件流,它是直接操作文件的流),处理流
抽象基类 字节流 字符流
输入流 InputStream Reader
输出流 outputstream Writer

FileReader,FileWriter

  • 访问文件的字符流
    读取流
  • a:实例化File对象,指明操作的文件
  • b:建立流
  • c:读取【or写入】数据
  • d:关闭流
    public static void test1() {
        //1. 实例化File对象,指明操作的文件
        File file = new File("hi.txt");
        //2. 建立流
        FileReader fs = null;
        try {
            fs = new FileReader(file);
            //3. 读取数据 方式一
            int read ;
            while ((read = fs.read()) != -1){
                System.out.print((char)read);   //helloWorld-1
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                //4.关闭流
                fs.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void test1() {
        //1. 实例化File对象,指明操作的文件
        File file = new File("hi.txt");
        //2. 建立流
        FileReader fs = null;
        try {
            fs = new FileReader(file);
            //3. 读取数据 方式二
            int read ;
            char[] cbuf = new char[5]; //这里一次放5个char字符串
            /** public int read(char cbuf[]):每次把读取的数据放入数组中,这样可以减少时间
             * 例如:外卖小哥送外卖,方式一相当于拿一个送走一个,方式二相当于一次拿5个,然后送走。这样省时
             * 这里hi.txt文本的数据是“helloWorld147”,共13个字符,需要三趟,其中第三趟读取了3个字符
             * */
           while ((read = fs.read(cbuf)) != -1){
               for (int i=0; i< read; i++) //若 i<cbuf.length,则输出结果:helloWorld147ld
                   System.out.print(cbuf[i]);
           }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                //4.关闭流
                fs.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

写入磁盘

  • 文件写入磁盘时,对应的File可以不存在的,并不会报异常;File对应的硬盘中的文件如果不存在,其输出的过程中,会自动创建此文件。
  • File对应的硬盘中的文件如果存在:如果流使用的构造器是:Filewriter(file,false)/Filewriter(file):对原有文件的覆盖;
    如果流使用的构造器是:Filewriter(file,true)不会对原有文件覆盖,而是在原来的文件基础上追加数据.
    public static void test2(){
        //1. 实例化File对象,指明操作的文件
        File file = new File("hi.txt"); //向hi.txt文件中写入数据
        FileWriter fw = null;
        try {
            //2. 建立流
            fw = new FileWriter(file);
            //3.写入
            fw.write("abc");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //4.关闭流
            try {
                if (null != fw)
                    fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

结论

  • 不能用字符流处理图片等字节类型的数据
  • 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
  • 对于非文本文件(.jpg,.mp3,.mp4,.avi,.ppt.…),使用字节流处理

FileInputStream,Fileoutputstream

  • 访问文件的字节流
    例如
//实现图片的复制
    public static void test3(){
        FileInputStream fis = null;
        FileOutputStream fos = null;

        //1.创建文件
        File file1 = new File("图片.jpg");
        File file2 = new File("图片复制.jpg");
        try {
            //2.构造流
            fis = new FileInputStream(file1);
            fos = new FileOutputStream(file2);
            //3.读取or写入
            int len;
            byte[] buf = new byte[5];
            while ((len = fis.read(buf)) != -1){
                fos.write(buf,0,len);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //4.关闭流
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null){
                try {
                    fos.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }

BufferedInputStream,BufferedOutputStream

  • 操作字节的缓存流(处理流)
    例如
    /**
     * 读取一幅图片并写入磁盘
     * idea中Ctrl+Alt+T,可以把代码包在一个块内,例如:try/catch
     * */
    public static void test4() {
        BufferedInputStream  bis= null;
        BufferedOutputStream bos = null;
        try {
            //1.创建文件
            File file1 = new File("图片.jpg");
            File file2 = new File("图片复制1.jpg");
            //2.创建流
            //2.1创建字节流
            FileInputStream  fis = new FileInputStream(file1);
            FileOutputStream fos = new FileOutputStream(file2);
            //2.2创建缓冲流
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);
            //3.读取并写入
            byte[] buffer = new byte[5];
            int len;
            while ((len = bis.read(buffer)) !=-1){
                bos.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.关闭流
            /**
             * 要求:先关闭外层的流,后关闭内层的流
             * 关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,可以省略。
             * */
            try {
                if (bos != null)
                    bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (bis!= null)
                    bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

BufferedReader,BufferedWriter

  • 操作字符的缓冲流(处理流)
    例如
    /**
     * 文本文件的复制
     * */
    public static void test5(){
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            //创建文件,创建流
            br = new BufferedReader(new FileReader(new File("hi.txt")));
            bw = new BufferedWriter(new FileWriter(new File("hi复制.txt")));
            //读取 写入
            int len;
            char[] cbuf = new char[1024];
            while ((len = br.read(cbuf)) != -1){
                bw.write(cbuf,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流
            if (bw != null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

InputStreamReader,OutputStreamWriter

  • 转换流(字符流)

  • InputStreamReader:将一个字节的输入流转换为字符的输入流

  • OutputStreamwriter:将一个字符的输出流转换为字节的输出流

标准输入输出流

  • System.in:标准的输入流,默认从键盘输入
  • System.out:标准的输出流,默认从控制台输出
    例子
/**
     * 此处用到:标准输入流,标准输出流,转换流.
     * 例:从控制台输入字符串,将其转换为大写的字符串
     * */
    public static void test6(){
        BufferedReader br = null; //读取字符流
        try {
            InputStream in = System.in; //从控制台接收数据
            InputStreamReader isr = new InputStreamReader(in);//用 转换输入流 将字节流转换为字符流
            br = new BufferedReader(isr);
            while (true){
                System.out.print("输入字符串: ");
                String s = br.readLine();
                if (s.equalsIgnoreCase("e")
                        || s.equalsIgnoreCase("exit")){
                    System.out.println("终止");
                    break;
                }
                System.out.println(s.toUpperCase());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close(); //只用关闭外层流即可
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
}

对象流

序列化:

  • ObjectOutputStream类保存基本类型数据或对象的机制
    反序列化
  • ObjectlnputStream类读取基本类型数据或对象的机制

序列化的例子

/**
   序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去
   该操作将hello,世界,写入到obj.data数据文件中,obj.data被持久化到磁盘中
* */
    public static void test7(){
        ObjectOutputStream oos = null;
        try {
            //1.操作文件
            oos = new ObjectOutputStream(new FileOutputStream("obj.data"));
            //2.写入
            oos.writeObject(new String("hello,世界"));
            oos.flush();//刷新操作
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3.关闭
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
   }

反序列化例子

/**
   反序列化:将磁盘文件中的对象还原为内存中的一个java对象
   该操作将hello,世界,从obj.data文件中读取出来
* */
    public static void test8(){
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("obj.data"));
            Object o = ois.readObject();
            String s = (String) o;
            System.out.println(s);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
   }

总结:

  • ObjectOutputStreamObjectlnputStream不能序列化statictransient修饰的成员变量
  • 对象要想序列化需要满足的要求:
    ①需要实现接口:Serializable
    ②当前类提供一个全局常量:serialVersionUID
    ③除了当前类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)
//反序列化一个类
    public static void test10(){
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("obj.data"));
            String s1 = (String) ois.readObject(); //读取顺序按照写入顺序读取
            System.out.println(s1);//你好

            Person person = (Person) ois.readObject();
            System.out.println(person);//Person{name='abc', age=22}
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
    //序列化一个类
    public static void test9(){
        ObjectOutputStream oos = null;
        try {
            //1.操作文件
            oos = new ObjectOutputStream(new FileOutputStream("obj.data"));
            //2.写入
            oos.writeObject(new String("你好"));
            oos.flush();
            oos.writeObject(new Person("abc",22));
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3.关闭
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

//person类需要序列化
class Person implements Serializable{

    private static final long serialVersionUID = -6849794470754667710L;

    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
//若是将Person类中成员变量加以static和transient修饰,则反序列化输出的结果如下:
String s1 = (String) ois.readObject(); //读取顺序按照写入顺序读取
System.out.println(s1);  //你好

Person person = (Person) ois.readObject();
System.out.println(person);   //Person{name='null', age=0}

RandomAccessFile

  • RandomAccessFile直接继承java.Lang.Object类,实现了DataInputDataoutput接口
  • RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
  • RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建,如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)
    该类有个方法seek(),用于定位指针位置。

IO流和网络

  • 在Java中使用InetAddress类代表IP
  • 端口号
    ①端口号标识正在计算机上运行的进程(程序)
    ②不同的进程有不同的端口号,被规定为一个16位的整数0~65535。
  • 端口分类:
    ①公认端口:0~1023。被预先定义的服务通信占用(如:HTTP占用端口80,FTP占用端口21,Telnet占用端口23)
    ②注册端口:1024~49151。分配给用户进程或应用程序。(如:Tomcat占用端口8080,MySQL占用端口3306,Oracle占用端口1521等)
    ③动态/私有端口:49152~65535
    端口号与IP地址的组合得出一个网络套接字:Socket
    简单例子
//客户端
    public static void test11() {
        Socket socket = null;
        OutputStream os = null;
        try {
            //1.实例化Socket对象,指定服务器端 IP和端口号
            socket = new Socket(InetAddress.getByName("127.0.0.1"), 8888);
            //2.获取一个输出流,用于发送数据
            os = socket.getOutputStream();
            //3.写出数据
            os.write("I am 客服端".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.关闭流
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //服务器端
    public static void test12() throws IOException {
        //1.实例化ServerSocket,指明自己的端口号
        ServerSocket ss = new ServerSocket(8888);
        //2.接收来自客户端Socket
        Socket socket = ss.accept();
        //3.获取输入流
        InputStream is = socket.getInputStream();
        //4.读数据
        //ByteArrayOutputStream属于字节流,若不用ByteArrayOutputStream,直接用new byte[5]数组,
        //当放入中文(占3个字节)第二个中文会出现乱码(每放入5个字节,就被覆盖了,直接放入下5个字节),
        //而ByteArrayOutputStream内部是byte buf[]数组,构造器创建时,默认构造32大小容量,当缩放字
        //节数超过32,会自动扩容(这里扩容2倍),其前面32字节不会被覆盖(相当于追加)。
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int len;
        byte[] bytes = new byte[5];
        while ((len = is.read(bytes)) != -1){
            baos.write(bytes,0,len);
        }
        System.out.println(baos.toString());
        //4.关闭流
        baos.close();
        is.close();
        socket.close();
        ss.close();
    }

URL编程

  • URL(Uniform Resource Locator):统一资源定位符,它表示Internet上某一资源的地址。
  • URL的基本结构由5部分组成: <传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表
    例如:http://192.168.1.100:8080/helloworld/index.jsp#a?username=abc&password=123
posted @ 2021-02-05 15:14  先生胡  阅读(108)  评论(0编辑  收藏  举报