Java 学习记录(8) IO流
一、Java中流的分类有哪些?
- 流从读取类型上来看分为字节流和字符流。
- 从流动方向上看又分为输入流和输出流两类。
- 从流从发生的源头看分为节点流和过滤流。其中节点流:直接操作目标设备对应的流,如文件流,标准输入输出流。过滤流:继承带有关键字Filter的流用于包装操作节点流,方便读写各种类型的数据。
二、字节流InputStream和OutputStream的子类分别有哪些?请举例说明其使用场景。与其对应的字符流分别有哪些?
InputStream
和OutputStream
是两个抽象类,其子类分布如下:
FileinputStream
和FileOutputStream
。
对应的字符流为 FileReader 和 FileWriter
FileInputStream
的作用在于通过指定文件路径的方式,将一个文件中的内容作为其他流的数据源,从而可以使用流的方式对文件进行读的操作;FileOutputStream
的作用在于通过指定文件路径的方式,将一个文件作为其他流的输出目的地,从而可使用流的方式对文件进行写操作。
- 字节数组流
ByteArrayInputStream
和ByteArrayOutputStream
对应的字符流为 CharArrayReader CharArrayWriter
字节数组流的作用是在字节数组和流之间搭建桥梁,ByteArrayInputStream
的构造方法ByteArrayInputStream(byte[] buf)
可以将字节数组构造成字节数组流的数据源,从而可以通过流的方式来读字节数组; ByteArrayOutputStream
的作用在于可以将任意多字
节的内容多次写入流中,最后整体转为一个字节数组。
- 管道流
PipedInputStream
和PipedOutputStream
对应的字符流为 PipedReader PipedWriter
管道用来把一个程序、线程和代码块的输出连接到另一个程序、线程和代码块的输入。管道输入流作为一个通信管道的接收端,管道输出流则作为发送端。管道流必须输入/输出并用,即在使用管道前,两者必须进行连接。
- 对象流
ObjectOutputStream
和ObjectInputStream
能够输入/输出对象的流称为对象流 - 过滤流
FilterInputStream
和FilterOutputStream
对应的字符流为:FilterReader 和FileterWriter
FilterInputStream
和FilterOutputStream
是两个抽象类,分别重写了父类InputStream
和OutputStream
的所有方法,对其他输入/输出流进行特殊处理,此外还提供了同步机制,使得某一时刻只有一个线程可以访问一个输入与输出流。要使用过滤流,首先必须把它连接到某个输人/输出节点流上。通常构造方法的参数中指定所要连接的节点流。
FilterInputStream( InputStream in); FilterOutputStream( OutputStream out);
- 缓冲流
BufferedInputStream
和BufferedOutputStream
对应的字符流为:BufferedReader 和 BufferedWriter
这两个类分别是FilterInputStream
和FilterOutputStream
的子类,实现了带缓冲的过滤流,它提供了缓冲机制,把节点流“捆绑”到缓冲流上,可以提高读写效率。使用于大文件的读写。
- 数据流
DatalnputStream
和DataOutputStream
这两个类分别是FilterInputStream
和FilterOutputStream
的子类,它们以统一方式读出或写出boolean、int、long、double等基本数据类型。此外,还提供了字符串读写的方法。 - 打印流
PrintStream
对应的字符流为PrintWriter
它能在输出时自动完成两项功能:如果输出字符串,则完成字符的编码过程,如果有汉字,能将汉字自动转化为操作系统本身的字符集GBK;另外,如果其输出路径上接有缓冲流,当调用println
方法或输出字符串中有换行标志时,则自动调用缓冲流的flush
方法。
三、字节流与字符流的转化是怎样的?Java对此提供了哪些支持?
字节流与字符流的转化桥梁在于类InputStreamReader
和OutputStreamWriter
- 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 }