YuCloud

紫菊气,飘庭户,晚烟笼细雨。

《谢新恩·冉冉秋光留不住》 - 五代 - 李煜

Java 学习记录(8) IO流

一、Java中流的分类有哪些?

  • 流从读取类型上来看分为字节流和字符流。
  • 从流动方向上看又分为输入流和输出流两类。
  • 从流从发生的源头看分为节点流和过滤流。其中节点流:直接操作目标设备对应的流,如文件流,标准输入输出流。过滤流:继承带有关键字Filter的流用于包装操作节点流,方便读写各种类型的数据。

二、字节流InputStream和OutputStream的子类分别有哪些?请举例说明其使用场景。与其对应的字符流分别有哪些?

InputStreamOutputStream是两个抽象类,其子类分布如下:

  • FileinputStream 和FileOutputStream
 对应的字符流为  FileReader 和  FileWriter

 

FileInputStream的作用在于通过指定文件路径的方式,将一个文件中的内容作为其他流的数据源,从而可以使用流的方式对文件进行读的操作;FileOutputStream的作用在于通过指定文件路径的方式,将一个文件作为其他流的输出目的地,从而可使用流的方式对文件进行写操作。

  • 字节数组流 ByteArrayInputStreamByteArrayOutputStream
对应的字符流为 CharArrayReader CharArrayWriter

 

字节数组流的作用是在字节数组和流之间搭建桥梁,ByteArrayInputStream的构造方法ByteArrayInputStream(byte[] buf)可以将字节数组构造成字节数组流的数据源,从而可以通过流的方式来读字节数组; ByteArrayOutputStream的作用在于可以将任意多字
节的内容多次写入流中,最后整体转为一个字节数组。

  • 管道流PipedInputStreamPipedOutputStream
对应的字符流为 PipedReader  PipedWriter

 

管道用来把一个程序、线程和代码块的输出连接到另一个程序、线程和代码块的输入。管道输入流作为一个通信管道的接收端,管道输出流则作为发送端。管道流必须输入/输出并用,即在使用管道前,两者必须进行连接。

  • 对象流ObjectOutputStreamObjectInputStream
    能够输入/输出对象的流称为对象流
  • 过滤流FilterInputStreamFilterOutputStream
对应的字符流为:FilterReader 和FileterWriter

 

FilterInputStreamFilterOutputStream是两个抽象类,分别重写了父类InputStreamOutputStream的所有方法,对其他输入/输出流进行特殊处理,此外还提供了同步机制,使得某一时刻只有一个线程可以访问一个输入与输出流。要使用过滤流,首先必须把它连接到某个输人/输出节点流上。通常构造方法的参数中指定所要连接的节点流。

FilterInputStream( InputStream in);
FilterOutputStream( OutputStream out);

  

 

  • 缓冲流BufferedInputStreamBufferedOutputStream
对应的字符流为:BufferedReader 和 BufferedWriter

 

这两个类分别是FilterInputStreamFilterOutputStream的子类,实现了带缓冲的过滤流,它提供了缓冲机制,把节点流“捆绑”到缓冲流上,可以提高读写效率。使用于大文件的读写。

  • 数据流DatalnputStreamDataOutputStream
    这两个类分别是FilterInputStream 和FilterOutputStream的子类,它们以统一方式读出或写出boolean、int、long、double等基本数据类型。此外,还提供了字符串读写的方法。
  • 打印流PrintStream
对应的字符流为PrintWriter

 

它能在输出时自动完成两项功能:如果输出字符串,则完成字符的编码过程,如果有汉字,能将汉字自动转化为操作系统本身的字符集GBK;另外,如果其输出路径上接有缓冲流,当调用println方法或输出字符串中有换行标志时,则自动调用缓冲流的flush方法。
在这里插入图片描述

三、字节流与字符流的转化是怎样的?Java对此提供了哪些支持?

字节流与字符流的转化桥梁在于类InputStreamReaderOutputStreamWriter

  • InputStreamReader 用于字节流->字符流
    它读取字节,并使用指定的编码将其解码为字符,它使用的字特集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
构造方法:
InputStreamReader (InputStream in)//创建一个使用默认字符集的InputStreamReader (InputStream in,String charsetName)//自己设定了

  

 

  • OutputStreamWriter 用于字符流->字节流。
    使用指定的编码将写入的字符编码为字节,它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
构造方法:
 OutputStreamWriter(OutputStream out) 
//OUtputstream 也是一个抽象类,真正做参数的是它的子类。例如:Fileoutputstream
OutputStreamWriter(OutputStream out,String charstname)
                    后面的参数指定字符集。

  

 

四、Java中的过滤流(流的装配)有什么作用?请举例说明常用的过滤流。

过滤流的具体作用请看(二)中关于过滤流的介绍。
常见的过滤流即为:BufferedInputStream 和BufferedOutputStream, 缓存作用,用于装配文件磁盘、网络设备、终端等读写开销大的节点流,提高读写性能。

五、什么是对象的序列化和反序列化?Java对此提供了哪些支持?

序列化: 对象的串行化(Serialization)将实现了Seriallizable接口的对象转换成一个字节序列。与之对应的反序列化就是把字节序列完全恢复为原来的对象。
支持: ObjectInputStream类和ObjectOutputStream类。

六、 Java的File类表示什么?有什么作用?

File 类表示的其实是文件和目录的具体路径,即FilePath。可以通过File类来对文件或者目录的创建和后续的读写操作。
具体请看下面的编程题:

七、Java对文件的读写分别提供了哪些支持?

读文件:FileInputStream FileReader
写:FileOutputStream FileWriter
提供对文件的随机访问支持:RandomAccessFile
具体请看编程题中的3和4。

八、编程题

一、完成下面的代码,要求建立一个缓冲区,将字节输入流中的内容转化为字符串。

代码如下(示例):

//完成下面的代码,要求建立一个缓冲区,将字节输入流中的内容转化为字符串。
import java.io.*;

public class test3 {
    public static void main(String[]args){
        File file =new File("E:\\name1.txt");
        try (FileInputStream fileInputStream = new FileInputStream(file)) {
            System.out.println(loadStream(fileInputStream));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static String loadStream(InputStream in) throws IOException {
        StringBuffer stringBuffer = new StringBuffer();
        InputStreamReader inputStreamReader = new InputStreamReader(in);
        char[]chars =new char[1024];
        int len;
        while((len=inputStreamReader.read(chars))!=-1){
            stringBuffer.append(String.valueOf(chars));
        }
        return String.valueOf(stringBuffer);
    }
}
}
/*
将数据读入字符数组中,然后利用StringBuffer类做中转站,将字符数组加入,最后就是把这个StringBuffer类转换为String返回
*/

  

二、编写程序,将一个字符串转为字节数组输入流,将这个流中所有小写字母换成大写字母并写入字节数组输出流中,再将数组输出流转为字符串。

代码如下(示例):

 1  2 /*
 3 * 编写程序,将一个字符串转为字节数组输入流,
 4 * 将这个流中所有小写字母换成大写字母并写入字节数组输出流中,
 5 * 再将数组输出流转为字符串*/
 6 
 7 import java.io.ByteArrayInputStream;
 8 import java.io.ByteArrayOutputStream;
 9 import java.util.Scanner;
10 public class test4 {
11     public static void main(String[]args){
12         String str1;
13         Scanner scanner = new Scanner(System.in);
14         str1=scanner.nextLine();
15         byte[]bytes=new byte[1024];
16         bytes=str1.getBytes();
17         try{
18             ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
19             ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
20             int len;
21             while((len=byteArrayInputStream.read())!=-1){
22                 if(len>='a'&&len<='z'){
23                     len=len+'A'-'a';
24                 }
25                 byteArrayOutputStream.write(len);
26             }
27             byteArrayInputStream.close();
28             String string =byteArrayOutputStream.toString();
29             System.out.println(string);
30         } catch (Exception e) {
31             e.printStackTrace();
32         }
33     }
34 }
35 
36 /*
37 利用字节数组输入流来读数据,每一次读取一个,并且同时做出转化,将小写转化为大写。再写入字节数组输出流,最后利用`toString`方法来转化为字符串,进行return
38 */

 

三、完成下面方法中的代码,方法中的参数为一个文本文件的名称,要求将文件中的内容转为字符串。

代码如下(示例):

 1  2 /*
 3 *完成下面方法中的代码,方法中的参数为一个文本文件的名称,
 4 * 要求将文件中的内容转为字符串。
 5 * */
 6 
 7 import java.io.File;
 8 import java.io.FileInputStream;
 9 import java.io.FileNotFoundException;
10 import java.io.IOException;
11 public class test5 {
12     public static void main(String[]args){
13         String  string="E:\\name1.txt";
14         System.out.println(loadFile(string));
15     }
16     public static String loadFile(String filename){
17         byte[] bytes = new byte[1024];
18         int len;
19         StringBuffer S = new StringBuffer();
20         try {
21             File file = new File(filename);
22             FileInputStream fileInputStream = new FileInputStream(file);
23             while((len=fileInputStream.read(bytes))!=-1){
24                 String str1 = new String(bytes,0,len); //一次读取一个字符数组的内容,我们要做的就是把这一部分字符数组里的内容
25                 S.append(str1);
26             }
27             fileInputStream.close();
28         }catch(FileNotFoundException e) {
29             e.printStackTrace();
30         } catch (IOException e) {
31             e.printStackTrace();
32         }
33         return String.valueOf(S);
34     }
35 }
36 /*
37 利用文件输入输出流,
38 每一次读取一个字符数组的内容,并利用`toString`方法转化为字符串,再利用`StringBuffer`类的`append`方法进行拼接。直到读到文件末尾。
39 最后就是把StringBuffer类转换为String。
40 
41 */

 

 

四、完成下面方法中的代码,将字符串contents中的内容写入文件filename中。

static public boolean saveFile(String filename, String contents) {}
代码如下(示例):

 1  2 /*
 3 * 完成下面方法中的代码,将字符串contents中的内容写入文件filename中。
 4 * */
 5 import java.io.*;
 6 import java.util.Scanner;
 7 public class test6 {
 8     public static void main(String[]args) throws FileNotFoundException {
 9         Scanner scanner = new Scanner(System.in);
10         String contents=scanner.nextLine();
11         //这是要写入的字符串
12         String filename ="E:\\coding\\JavaLearningCode\\java输入输出流的编写\\test6.txt";
13        System.out.println(saveFile(filename,contents));
14     }
15     public static boolean saveFile(String filename, String contents) throws FileNotFoundException {
16        try (FileOutputStream fileOutputStream = new FileOutputStream(filename)) {
17            byte[] bytes=contents.getBytes();
18            fileOutputStream.write(bytes);
19        } catch (IOException e) {
20            e.printStackTrace();
21        }
22         return true;
23     }
24 }
25 /*
26 先把字符串转化为字符数组,再利用字节输出流的写文件方法写入即可。
27 
28 */

 

五、socket 套接字有一个方法getInputStream(),其含义是得到从网络上传过来的数据流。现要求编写一段程序,将接收的数据存入文件。

代码如下(示例):

 1  2 
 3 import java.io.*;
 4 import java.net.Socket;
 5 
 6 /*
 7 socket 套接字有一个方法getInputStream()
 8 其含义是得到从网络上传过来的数据流。现要求编写
 9 一段程序,将接收的数据存入文件。
10  */
11 public class test7 {
12     public static void main(String[]args) throws IOException {
13         Socket socket=new Socket("127.0.0.1",4700);
14         BufferedReader sin =new BufferedReader(new InputStreamReader(socket.getInputStream()));
15         File file = new File("E:\\coding\\JavaLearningCode\\java输入输出流的编写\\test7.txt");
16         FileOutputStream out = new FileOutputStream(file);
17         BufferWriter bw=new BufferWriter(new OutputStreamWriter(out)); 
18         String readline = sin.readLine();
19         bw.write(readline);
20         sin.close();
21         bw.close();
22         socket.close();
23     }
24 }
25 /*
26 利用字符输输入流和字符输出流来实现,
27 构建字符输入流对象 sin和字符输出流对象 bw。其中用到了OutputStreamWriter和InputStreamReader 做中转。
28 最后完成了读入和写。
29 */

 

六、编写程序实现文件查找功能。提供两个参数,第一个参数为查找的起始路径,第二个参数为要查找的文件名称。如果找到,则给出文件的完整路径,否则提示文件不存在。

代码如下(示例):

 1 2 import java.io.File;
 3 public class test8 {
 4     public static void main(String args[]){
 5        String str1="E:\\test1";
 6        String str2="1.txt";
 7        FindFile(String str1,String str2)
 8     }
 9     public static void FindFile(String str1,String str2){
10         File file1 =new File(str1);
11         File[] files=file1.listFiles();
12         for(File file2:files){
13             if(file2.isFile()){
14                 String string1 = file2.getAbsolutePath();
15                 int firstindex=string1.lastIndexOf('\\');
16                 String substring=string1.substring(firstindex+1);
17                 if(substring.equals(str2)){
18                     System.out.println(string1);
19                     return;
20                 }
21             }else if(file2.isDirectory()){
22                 String string = file2.getAbsolutePath();
23                 FindFile(string,str2);
24             }
25         }
26     }
27 }
28 /*
29 先对起始路径构建Filec对象,并且利用`listFiles()`方法来得到所有的子目录,或者文件,下一步就是判断,是文件?是,则利用字符串拼接和比对`equals()`方法来判断文件名是否相同。
30 否则,对于目录,我们继续向下递归。
31 */

 

七、利用串行化技术和Socket通信,将一个客户端构造的对象送到服务端,并输出该对象的属性值。

 1 --------第一个User类-----------------
 2 
3 4 import java.io.Serializable; 5 public class User implements Serializable { 6 7 private static final long serialVersionUID = 1L; 8 String Name; 9 String Password; 10 User()//默认构造函数 11 { 12 Name="null"; 13 Password="00000"; 14 } 15 User(String name,String password)//带参数的构造函数 16 { 17 Name=name; 18 Password=password; 19 } 20 void setName(String name) {Name=name;} 21 void setPassword(String password) {Password=password;} 22 String getName() {return Name;} 23 String getPassword() {return Password;} 24 } 25 26 ----------------下面是第二个类,客户端------- 27 package 作业题9; 28 29 import java.io.*; 30 import java.net.Socket; 31 32 public class TalkClient { 33 public static void main(String[] args) throws IOException{ 34 Socket socket = null; 35 try { 36 socket = new Socket("127.0.0.1", 4700); 37 } catch (IOException e) { 38 e.printStackTrace(); 39 } 40 User u1 = new User(); 41 u1.setName("Tommy"); 42 u1.setPassword("1234567"); //赋值 43 //把对象串行化为可输出的形式,输入到Socket的输出流里面 44 ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); 45 out.writeObject(u1);//以串行化方式写入这个对象 46 System.out.println("successful!"); 47 out.flush(); 48 out.close();//超级重要,要是没有close来正常退出,服务器端就会被意外中止,导致出错。 49 } 50 } 51 52 53 -------------------------------下面是服务器端--------- 5455 56 import java.io.*; 57 import java.net.*; 58 59 public class MultiTalkServer { 60 public static void main(String[] args) throws ClassNotFoundException, IOException { 61 ServerSocket server; 62 Socket socket = null; 63 try { 64 server = new ServerSocket(4700); 65 socket = server.accept(); 66 ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); 67 System.out.println("连接成功!"); 68 User u2 = (User) in.readObject();//接受一个被串行化的对象,赋值给u2 69 System.out.println("Name: "+ u2.getName() + " Password: " + u2.getPassword()); 70 in.close(); 71 } catch (IOException e) { 72 e.printStackTrace(); 73 } 74 } 75 }

 

posted @ 2020-12-07 21:27  tree[3]  阅读(215)  评论(0编辑  收藏  举报