主要内容
1.编码问题
2.File类的使用
3.RandomAccessFile的使用
4.I/O 输入输出流
编码问题:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 import java.io.UnsupportedEncodingException; 2 3 public class 编码问题 { 4 public static void main(String[] args) { 5 // 我们项目的默认编码是GBK 6 String s = "测试 ABC"; 7 byte[] byte1 = s.getBytes();// 转换成的字节序列用的是项目默认的编码gbk 8 for (byte b : byte1) { 9 // 1 byte = 8 位 //toHexString这个函数是把字节(转换成了Int)以16进制的方式显示 10 System.out.print(Integer.toHexString(b & 0xff) + " ");// & 11 // 0xff是为了把前面的24个0去掉只留下后八位 12 } 13 14 try { 15 // 也可以转换成指定的编码 16 byte[] bytes1 = s.getBytes("gbk"); 17 System.out.println(new String(bytes1)); 18 } catch (UnsupportedEncodingException e) { 19 // TODO Auto-generated catch block 20 e.printStackTrace(); 21 } 22 /** 23 * gbk编码: 中文占用两个字节,英文占用一个字节 utf-8编码:中文占用三个字节,英文占用一个字节 24 * java是双字节编码,是utf-16be编码 utf-16be编码:中文占用两个字节,英文占用两个字节 25 * 当你的字节序列是某种编码时,这个时候想把字节序列变成字符串,也需要用这种编码方式,否则会出现乱码 26 */ 27 try { 28 byte[] byte2 = s.getBytes("utf-16be"); 29 String s2 = new String(byte2, "utf-16be"); 30 System.out.println(s2); 31 } catch (UnsupportedEncodingException e) { 32 // TODO Auto-generated catch block 33 e.printStackTrace(); 34 } 35 /** 36 * 文本文件就是字节序列,可以是任意编码的字节序列 37 * 如果我们在中文机器上直接创建文本文件,那么该文件只认识ANSI编码(例如直接在电脑中创建文本文件) 38 */ 39 40 /** 41 * byte转int的时候为什么非要先&0xff计算出来才是正确答案? 42 * 首先,java中的二进制采用的是补码形式,并非原码或反码,这3个概念要搞清楚; 43 * 其次,byte占8位,int占32位,将byte强制转换为int型时,如果没有做 & 44 * 0xff运算,且byte对应的值为负数的话,就会对高位3个字节进行补位,这样就有可能出现补位误差的错误。 45 * 举例来说,byte型的-1,其二进制(补码)为11111111(即0xff),转换成int型,值也应该为-1,但经过补位后, 46 * 得到的二进制为11111111111111111111111111111111(即0xffffffff),这就不是-1了,对吧? 47 * 而0xff默认是int型,所以,一个byte跟0xff相与,会先将那个byte转化成int型运算,这样,结果中的高位3个字节就总会被清0, 48 * 于是结果就是我们想要的了~ 49 */ 50 51 } 52 53 }
File类的使用:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 import java.io.File; 2 import java.io.IOException; 3 4 public class FileDemo { 5 6 /** 7 * @param args 8 */ 9 public static void main(String[] args) { 10 // 了解构造函数的情况 查帮助ALT+/ 11 File file = new File("E:\\javaio\\imooc"); 12 // 判断文件/文件夹是否存在 13 // System.out.println(file.exists()); 14 if (!file.exists()) 15 file.mkdir(); // file.mkdirs()如果文件不存在,直接创建文件夹 16 // mkdir创建的一级目录,如果需要创建多级目录可以使用mkdirs() 17 else 18 file.delete(); 19 20 // 是否是一个目录 如果是目录返回true,如果不是目录or目录不存在返回的是false 21 System.out.println(file.isDirectory()); 22 // 是否是一个文件 23 System.out.println(file.isFile()); 24 25 // File file2 = new File("e:\\javaio\\日记1.txt"); 26 File file2 = new File("e:\\javaio", "日记1.txt"); 27 if (!file2.exists()) 28 try { 29 file2.createNewFile(); 30 } catch (IOException e) { 31 // TODO Auto-generated catch block 32 e.printStackTrace(); 33 } 34 else 35 file2.delete(); 36 // 常用的File对象的API 37 System.out.println(file);// file.toString()的内容 38 System.out.println(file.getAbsolutePath()); 39 System.out.println(file.getName()); 40 System.out.println(file2.getName()); 41 System.out.println(file.getParent()); 42 System.out.println(file2.getParent()); 43 System.out.println(file.getParentFile().getAbsolutePath()); 44 } 45 46 }
遍历目录
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 import java.io.File; 2 import java.io.IOException; 3 4 //列出File的一些常用操作比如过滤,遍历等操作 5 public class FileUtils { 6 /** 7 * 列出指定指定目录下(包括其子目录)的所有文件 8 * 9 * @param dir 10 * @throws IOException 11 */ 12 public static void listDirectory(File dir) throws IOException { 13 if (!dir.exists()) { 14 throw new IllegalArgumentException("目录:" + dir + "不存在"); 15 } 16 if (!dir.isDirectory()) { 17 throw new IllegalArgumentException(dir + "不是目录"); 18 } 19 20 // String[] fileNames = 21 // dir.list();//返回的是字符串数组,list()方法用于列出当前目录下的子目录和文件,直接子的名称,不包含子目录下的内容 22 // for (String string : fileNames) { 23 // System.out.println(dir+"\\"+string); 24 // } 25 // 26 // 如果要遍历子目录下的内容就需要构造成File对象做递归操作,File提供了直接返回File对象的API 27 File[] files = dir.listFiles();// 返回的是直接子目录(文件)的抽象 28 if (files != null && files.length > 0) {// 确定存在子目录 29 for (File file : files) { 30 if (file.isDirectory()) { 31 // 递归 32 listDirectory(file); 33 } else { 34 System.out.println(file); 35 } 36 } 37 } 38 } 39 }
RandomAccessFile的使用
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 import java.io.File; 2 import java.io.IOException; 3 import java.io.RandomAccessFile; 4 import java.util.Arrays; 5 6 public class RafDemo { 7 8 /** 9 * @param args 10 */ 11 public static void main(String[] args) throws IOException { 12 File demo = new File("demo"); 13 if (!demo.exists()) 14 demo.mkdir(); 15 File file = new File(demo, "raf.dat"); 16 if (!file.exists()) 17 file.createNewFile(); 18 19 RandomAccessFile raf = new RandomAccessFile(file, "rw"); 20 // 指针的位置 21 System.out.println(raf.getFilePointer()); 22 23 raf.write('A');// 只写了一个字节 24 System.out.println(raf.getFilePointer()); 25 raf.write('B'); 26 27 int i = 0x7fffffff; 28 // 用write方法每次只能写一个字节,如果要把i写进去就得写4次 29 raf.write(i >>> 24);// 高8位 30 raf.write(i >>> 16); 31 raf.write(i >>> 8); 32 raf.write(i); 33 System.out.println(raf.getFilePointer()); 34 35 // 可以直接写一个int 36 raf.writeInt(i); 37 38 String s = "中"; 39 byte[] gbk = s.getBytes("gbk"); 40 raf.write(gbk); 41 System.out.println(raf.length()); 42 43 // 读文件,必须把指针移到头部 44 raf.seek(0); 45 // 一次性读取,把文件中的内容都读到字节数组中 46 byte[] buf = new byte[(int) raf.length()]; 47 raf.read(buf); 48 49 System.out.println(Arrays.toString(buf)); 50 for (byte b : buf) { 51 System.out.println(Integer.toHexString(b & 0xff) + " "); 52 } 53 raf.close(); 54 } 55 56 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
import java.io.IOException; import java.io.RandomAccessFile; public class RafReadDemo { /** * @param args */ public static void main(String[] args) throws IOException { // TODO Auto-generated method stub RandomAccessFile raf = new RandomAccessFile("demo/raf.dat", "r"); raf.seek(2); int i = 0; int b = raf.read();// 读取到一个字节 System.out.println(raf.getFilePointer()); i = i | (b << 24); b = raf.read(); i = i | (b << 16); b = raf.read(); i = i | (b << 8); b = raf.read(); i = i | b; System.out.println(Integer.toHexString(i)); raf.seek(2); i = raf.readInt(); System.out.println(Integer.toHexString(i)); raf.close(); } }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 import java.io.File; 2 import java.io.IOException; 3 import java.io.RandomAccessFile; 4 public class RandomAccessFileSeriaDemo { 5 6 /** 7 * @param args 8 */ 9 public static void main(String[] args) throws IOException { 10 // TODO Auto-generated method stub 11 File demo = new File("demo1"); 12 if (!demo.exists()) 13 demo.mkdir(); 14 File file = new File(demo, "raf.dat"); 15 if (!file.exists()) 16 file.createNewFile(); 17 // 打开文件,进行随机读写 18 RandomAccessFile raf = new RandomAccessFile(file, "rw"); 19 /* 序列化 */ 20 int i = 0x7ffffff; 21 raf.write(i >>> 24); 22 raf.write(i >>> 16); 23 raf.write(i >>> 8); 24 raf.write(i); 25 System.out.println(raf.getFilePointer()); 26 27 /* 反序列化 */ 28 raf.seek(0); 29 int b = raf.read(); 30 i = i | (b << 24); 31 b = raf.read(); 32 i = i | (b << 16); 33 b = raf.read(); 34 i = i | (b << 8); 35 b = raf.read(); 36 i = i | b; 37 System.out.println(Integer.toHexString(i)); 38 raf.close(); 39 } 40 } 41 42 RandomAccessFileSeriaDemo
I/O 输入输出流
流的定义:
流就是程序和设备之间嫁接起来的一根用于数据传输的管道,这个管道上有很多按钮,不同的按钮可以实现不同的功能。
这根用于数据传输的管道就是流,流就是一根管道
输入时,程序在源(文件,网络,内存)上打开一个流,然后如图一个一个顺序读。写也一样。
流的分类和使用:
四大基本抽象流,文件流,缓冲流,转换流,数据流,Print流,Object流。
JAVA.io 包中定义了多个流类型(类或抽象类)来实现输入/输出功能;可以从不同角度对其进行分类:
*按数据流的方向不用可以分为输入流和输出流
*按处理数据单位不同可以分为字节流和字符流
*按照功能不同可以分为节点流和处理流
JAVA中所提供的的所有流类型位于包JAVA.io内,都分别继承自以下四种抽象流类型:
节点流与处理流:
节点流可以从一个特定的数据源(节点)读取数据(如:文件,内存)
处理流是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。
节点流也叫原始流,处理流也叫包裹流。
流与类的关系:
如果一个类是用作设备和程序之间的数据传输,则这个类有一个新的名字叫做流
流一定是类,但类不一定是流
四大基本流的介绍
输入流,输出流,字节流,字符流
InputStream和OutputStream读写数据的单位是一个字节
Reader和Writer读写数据的单位是一个字符
在JAVA中一个字符占两个字节
InputStream,OutputStream,Reader,Writer都是抽象类,或者说都是抽象流,通常我们使用的都是它们的子类,凡是以Stream结尾的都是字节流。
InputStream 流中的常用方法:
OutputStream 流中的常用方法:
Reader 流中的常用方法:
Writer 流中的常用方法:
文件流
文件流包括:
FileInputStream FileOutputStream --字节流
FileReader FileWriter --字符流
实例:读取一个文件的内容并将其输出到显示器上,并统计读取的字节个数
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /* 2 利用FileReader流来读取一个文件中的数据,并在显示器上输出! 3 */ 4 5 import java.io.*; 6 7 public class TestFileReader { 8 public static void main(String[] args) { 9 FileReader fr = null; 10 11 try { 12 fr = new FileReader("C:\\Documents and Settings\\others\\桌面\\java\\TestFileReader.java"); 13 int cnt = 0; 14 int ch; 15 16 while (-1 != (ch = fr.read())) // 20行 17 { 18 System.out.print((char) ch); // System.out.print(int ch); 19 // 这是在显示器上输出ch的整数值,所以必须的进行类型转化,我们需要输出的是ch所代表的整数对应的字符 20 ++cnt; 21 } 22 23 System.out.printf("总共从TestFileReader.java文件中读取了%d个字符", cnt); 24 } catch (FileNotFoundException e) { 25 System.out.println("找不到文件!"); 26 System.exit(-1); 27 } catch (IOException e) { 28 System.out.println("文件读取失败!"); 29 System.exit(-1); 30 } 31 } 32 }
FileInputStream的使用
FileReader的使用
字节流与字符流的区别:
FileInputStream 和FileOutputStream 可以完成所有格式文件的复制
FileReader和FileWriter只可以完成文本文件的复制,却无法完成其他格式文件的复制
因为字节是不需要解码和编码的,将字节转化为字符才存在解码和编码的问题
字节流可以从所有格式的设备中读写数据,但字符流只能从文本格式的设备中读写数据
实例:编程实现文件的复制
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /* 2 利用FileInputStream 和 FileOutputStream 可以完成所有格式文件的赋值 3 因为字节是不需要解码和编码的,将字节转化为字符才存在解码的问题 4 本程序完成了音频文件的复制 5 */ 6 7 import java.io.*; 8 9 public class TestFileInputStreamOutputStreamCopy { 10 public static void main(String[] args) { 11 FileInputStream fi = null; 12 FileOutputStream fo = null; 13 14 try { 15 fi = new FileInputStream("E:\\综艺\\歌曲\\卡农.mp3"); 16 fo = new FileOutputStream("d:/share/Output.txt"); //使用播放器可正常播放该文件 17 int ch; 18 19 while (-1 != (ch = fi.read())) { 20 fo.write(ch); 21 } 22 } catch (FileNotFoundException e) { 23 System.out.println("文件没有找到!"); 24 System.exit(-1); 25 } catch (IOException e) { 26 System.out.println("文件读写错误!"); 27 System.exit(-1); 28 } finally { 29 try { 30 if (null != fi) { 31 fi.close(); 32 fi = null; 33 } 34 if (null != fo) { 35 fo.close(); 36 fo = null; 37 } 38 } catch (Exception e) { 39 e.printStackTrace(); 40 System.exit(-1); 41 } 42 } 43 44 System.out.println("文件复制成功!"); 45 } 46 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /* 2 本程序证明了 FileReader 和 FileWriter 只可以完成文本文件的复制, 3 却无法完成音频格式文件的复制 4 */ 5 6 import java.io.*; 7 8 public class TestFileReaderWriterCopy { 9 public static void main(String[] args) { 10 FileReader fi = null; 11 FileWriter fo = null; 12 13 try { 14 fi = new FileReader("E:\\综艺\\歌曲\\卡农.mp3"); 15 fo = new FileWriter("d:/share/Output.txt"); // Output.txt使用播放器打开失败! 16 // 本程序证明了FileWriter 和 17 // FileReader 18 // 无法完成音频文件的复制,实际上FileWriter 19 // 和 FileReader 20 // 只能完成文本文件的复制 21 int ch; 22 23 while (-1 != (ch = fi.read())) { 24 fo.write(ch); 25 } 26 } catch (FileNotFoundException e) { 27 System.out.println("文件没有找到!"); 28 System.exit(-1); 29 } catch (IOException e) { 30 System.out.println("文件读写错误!"); 31 System.exit(-1); 32 } finally { 33 try { 34 if (null != fi) { 35 fi.close(); 36 fi = null; 37 } 38 if (null != fo) { 39 fo.close(); 40 fo = null; 41 } 42 } catch (Exception e) { 43 e.printStackTrace(); 44 System.exit(-1); 45 } 46 } 47 48 System.out.println("文件复制成功!"); 49 } 50 }
缓冲流
缓冲流就是带有缓冲区的输入输出流
缓冲流可以显著的减少我们对IO访问的次数,保护我们的硬盘
缓冲流本事就是处理流(包裹流),缓冲流必须得依附于节点流(原始流)
处理流包裹在原始节点流上的流,相当于包裹在管道上的管道
缓冲流要"套接"在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了一些新的方法。JAVA提供了四种缓冲流,其常用的构造方法为:
BufferedOutputStream 和 BufferedInputStream
BufferedOutputStream :带有缓冲的输出流,允许一次向硬盘写入多个字节的数据。
BufferedInputStream:带缓冲的输入流,允许一次向程序中读入多个字节的数据。
BufferedOutputStream 和 BufferedInputStream都是包裹流,必须依附于OutputStream和InputStream
例子:利用BufferedOutputStream 和 BufferedInputStream 完成大容量文件的复制,这远比单纯利用FileInputStream和FileOutputStream要快的多
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /* 2 利用BufferedOutputStream 和 BufferedInputStream完成大容量文件的复制 3 这远比单纯利用 FileInputStream 和 FileOutputStream 要快得多 4 5 BufferedOutputStream 和 BufferedInputStream 都是包裹流,必须的依附于 6 InputStream 和 OutputStream 7 */ 8 9 import java.io.*; 10 11 public class TestBufferedInputStreamOutputStreamCopy { 12 public static void main(String[] args) { 13 BufferedOutputStream bos = null; 14 BufferedInputStream bis = null; 15 16 try { 17 bos = new BufferedOutputStream(new FileOutputStream("e:/OutputView.txt")); // bos 18 // 输出流有个默认的缓冲区,大小为32个字节 19 20 bis = new BufferedInputStream(new FileInputStream("c:\\[高清在线www.66ys.cn]海底总动员DVD中英字幕.rmvb")); // bis 21 // 输入流有个默认的缓冲区,大小为32个字节 22 byte[] buf = new byte[1024]; 23 int len = bis.read(buf, 0, 1024); // 一定要注意,这不是从buf中读数据,而是从bis所关联到的D:\\综艺\\电影\\猫和老鼠\\CD4.rmvb文件中读取数据,并将读取的数据写入bis自己的默认缓冲区中,然后再将缓冲区的内容写入buf数组中,每次最多向buf数组中写入1024个字节,返回实际写入buf数组的字节个数,如果读到了文件的末尾,无法再向buf数组中写入数据,则返回-1 24 while (-1 != len) { 25 bos.write(buf, 0, len); // 不是写入buf数组,而是将buf数组中下标从0开始的到len-1为止的所有数据写入bos所关联到的"d:/share/OutputView.txt"文件中 26 len = bis.read(buf); // bis.read(buf); 等价于 bis.read(buf, 0, 27 // buf.length); 28 } 29 bos.flush(); 30 bis.close(); 31 bos.close(); 32 } catch (FileNotFoundException e) { 33 System.out.println("没有找到文件!"); 34 System.exit(-1); 35 } catch (IOException e) { 36 System.out.println("文件读写错误!"); 37 System.exit(-1); 38 } 39 40 System.out.println("文件复制成功!"); 41 } 42 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /* 2 本程序读写速度要慢于 "TestBufferedInputStreamOutputStreamCopy.java" 程序 3 即: 4 利用BufferedOutputStream 和 BufferedInputStream完成大容量文件的复制 5 这远比单纯利用 FileInputStream 和 FileOutputStream 要快得多 6 7 BufferedOutputStream 和 BufferedInputStream 都是包裹流,必须的依附于 8 OutputStream 和 OutputStream 9 */ 10 11 import java.io.*; 12 13 public class TestBufferedInputStreamOutputStreamCopy_2 { 14 public static void main(String[] args) { 15 FileOutputStream bos = null; 16 FileInputStream bis = null; 17 18 try { 19 bos = new FileOutputStream("e:/OutputView.txt"); 20 bis = new FileInputStream("c:\\[高清在线www.66ys.cn]海底总动员DVD中英字幕.rmvb"); 21 22 byte[] buf = new byte[1024]; 23 int len = bis.read(buf, 0, 1024); 24 while (-1 != len) { 25 bos.write(buf, 0, len); 26 len = bis.read(buf); 27 } 28 bos.flush(); 29 bis.close(); 30 bos.close(); 31 } catch (FileNotFoundException e) { 32 System.out.println("没有找到文件!"); 33 System.exit(-1); 34 } catch (IOException e) { 35 System.out.println("文件读写错误!"); 36 System.exit(-1); 37 } 38 39 System.out.println("文件复制成功!"); 40 } 41 }
一定要注意,bis.read(buf,0,1024);这不是从buf中读数据,而是从bis所关联到的“D:\\综艺\\电影\\猫和老鼠\\CD4.rmvb”文件中读取数据,并将读取的数据写入bis自己的默认缓冲区中,然后再将缓冲区的内容写入buf数组中,每次最多向buf数组中写入1024个字节,返回实际写入buf数组的字节个数,如果读到了文件的末尾,无法再向buf数组中写入数据,则返回-1
BufferedInputStream流中有public int read(byte[] b)方法用来把从当前流关联到的设备中读取出来的数据存入一个byte数组中
BufferedOutputStream 流中有public int write(byte[] b)方法用来把byte数组中的数据输出来当前流所关联到的设备中
如果我们希望用BufferedInputStream 和 BufferedOutputStream 完成“将一个设备中的数据导入另一个设备中”,我们就应该定义一个临时的byte类型的数据,用这个临时数组作为输入流和输出流进行交互的中转枢纽。
BufferedReader 和 BufferedWriter
实例:利用BufferedReader 和 BufferedWriter完成文本文件的复制
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /* 2 利用 BufferedReader 和 BufferedWriter 完成文本文件的复制 3 */ 4 import java.io.*; 5 6 public class TestBufferedReaderWriterCopy { 7 public static void main(String[] args) { 8 BufferedReader br = null; 9 BufferedWriter bw = null; 10 11 try { 12 br = new BufferedReader( 13 new FileReader("C:\\Documents and Settings\\others\\桌面\\java\\TestBufferedReaderWriterCopy.java")); 14 bw = new BufferedWriter(new FileWriter("d:/share/Writer.txt")); 15 String str = null; 16 17 while (null != (str = br.readLine())) // br.readLine()读取一行字符,但会将读取的换行符自动丢弃,即返回的String对象中并不包括换行符 18 { 19 bw.write(str); 20 bw.newLine(); // 写入一个换行符 这行不能省 21 } 22 bw.flush(); 23 } catch (FileNotFoundException e) { 24 e.printStackTrace(); 25 System.exit(-1); 26 } catch (IOException e) { 27 e.printStackTrace(); 28 System.exit(-1); 29 } finally { 30 try { 31 bw.close(); 32 br.close(); 33 } catch (IOException e) { 34 e.printStackTrace(); 35 System.exit(-1); 36 } 37 } 38 } 39 }
数据流DataInputStream DataOutputStream
DataInputStream能够以一种与机器无关的方式,直接从底层字节输入流读取JAVA基本类型和String类型的数据。常用方法包括:
DataInputStream 是包裹流,必须依附于InputStream
DataOutputStream能够以一种机器无关的方式,直接将JAVA基本类型和String类型数据写出到其他的字节输出流。常用方法包括:
DataOutputStream 是包裹流,它必须依附于OutputStream
数据流实例:
编程实现将long类型数据写入byte数组,然后再从byte数组中吧该数据读出来{
*这是Socket编程中经常要完成的功能。
*因为网络编程中经常要把数据存入byte数组中,然后把byte数组打包成数据包(DatagramPacket),再把数据包经过网络传输到目的机,目的机再从byte数组中把原数值型数据还原回来。
}
本程序要使用到:
DataInputStream
DataOutputStream
ByteArrayInputStream
ByteArrayOutputStream
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /* 2 功能:把一个long类型的数据写入byte数组中,然后再从byte数组中读取出 3 这个long类型的数据 4 5 因为网络编程中经常要把数值型数据存入byte数组中然后打包成 6 DatagramPacket经过网络传输到目的机,目的机再从byte数组中 7 把原数值型数据还原回来 8 9 目的: ByteArrayOutputStream DataOutputStream ByteInputStream DataInputStream 流的使用 10 记住: DataOutputStream流中的writeLong(long n)是把n变量在内存 11 中的二进制代码写入该流所连接到的设备中 12 13 注意:查API文档得知: 14 构造 ByteArrayOutputStream 对象时不需要也不能指定缓冲数组,因为缓冲数组默认已经内置好了 15 构造 ByteArrayInputStream 对象时必须的指定缓冲数组是谁! 16 */ 17 18 import java.io.*; 19 20 public class TestByteArrayOutputStream1 21 { 22 public static void main(String args[]) throws Exception 23 { 24 long n = 9876543210L; 25 ByteArrayOutputStream baos = new ByteArrayOutputStream(); //9行 API:"public ByteArrayOutputStream(): 创建一个新的 byte 数组输出流。缓冲区的容量最初是 32 字节,如有必要可增加其大小。 " 26 //9行代码一旦执行完毕,意味着两点: 1、在内存中生成了一个大小为32个字节的byte数组 2、有一根叫做baos的管道已链接到了该byte数组中,并且可以通过这个管道向该byte数组中写入数据 27 //虽然此时可以通过baos向baos所连接到的在内存中分配好的byte数组中写入数据,但是ByteArrayOutputStream流并没有提供可以直接把long类型数据直接写入ByteArrayOutputStream流所连接到的byte数组中的方法, 简单说我们没法通过baos向baos所连接到的byte数组中写入long类型的数据, 查API文档可以发现: ByteArrayOutputStream流中并没有类似writeLong()这样的方法,但是DataOutputStream流中却有writeLong() writeFloat()等方法 28 DataOutputStream dos = new DataOutputStream(baos); 29 30 dos.writeLong(n); //把n变量所代表的10000L在内存中的二进制代码写入dos所依附的baos管道所连接到的内存中的大小为32字节的byte数组中,由运行结果来看,这是二进制写入,既不是把10000L转化为字符'1' '0' '0' '0' '0'写入byte数组中,而是把10000L在内存中的总共8个字节的二进制代码写入byte数组中 31 32 dos.flush(); 33 byte[] buf = baos.toByteArray(); //DataOutputStream 流中并没有toByteArray()方法,但是ByteArrayOutputStream 流中却有toByteArray()方法, 所以不可以把baos 改为dos,否则编译时会出错! ByteArrayOutputStream流中toByteArray()方法的含义,摘自API“创建一个新分配的 byte 数组。其大小是此输出流的当前大小,并且缓冲区的有效内容已复制到该数组中” 34 35 //利用ByteArrayInputStream 和 DataInputStream 可以从byte数组中得到原long类型的数值10000L 36 ByteArrayInputStream bais = new ByteArrayInputStream(buf); 37 DataInputStream dis = new DataInputStream(bais); 38 long l = dis.readLong(); 39 40 System.out.println("l = " + l); 41 dos.close(); 42 } 43 } 44 /* 45 在JDK 1.6中的运行结果是: 46 ---------------- 47 l = 9876543210 48 ---------------- 49 */
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /* 2 功能: 3 将long类型数据写入byte数组,然后在从byte数组中把该数据读出来 4 */ 5 6 import java.io.*; 7 8 public class TestByteArrayOutputStream2 9 { 10 public static void main(String[] args) throws Exception 11 { 12 long n = 1234567; 13 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 14 DataOutputStream dos = new DataOutputStream(baos); 15 dos.writeLong(n); 16 17 byte[] buf = baos.toByteArray(); 18 ByteArrayInputStream bis = new ByteArrayInputStream(buf); 19 DataInputStream dis = new DataInputStream(bis); 20 long n2 = dis.readLong(); 21 System.out.println("n2 = " + n2); 22 23 dos.close(); 24 dis.close(); 25 } 26 }
转换流:OutputStreamWriter InputStreamReader
OutputStreamWriter 流是把OutputStream流 转化成Writer流的流
InputStreamReader 流是把InputStream流转化为Reader
OutputStreamWriter 和 InputStreamReader都是包裹流
实例:如何将键盘输入的字符组成字符串直接赋给String对象。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /* 2 如何将键盘输入的字符组成字符串直接赋给String 对象 3 4 预备知识: 5 -------------------------------- 6 Reader FileReader InputStream FileInputStream BufferedInputStream 7 流中都没有 readLine 方法 8 DataInputStream 流中有 readLine方法,但已经 被标记为过时 9 BufferedReader 流中有readLine方法,并且该方法是可以正确被使用的 10 -------------------------------- 11 */ 12 13 import java.io.*; 14 15 public class TestStringInput 16 { 17 public static void main(String[] args) 18 { 19 String str = null; 20 BufferedReader br = new BufferedReader ( //21行 21 new InputStreamReader(System.in) 22 ); //23行 查API:从21行到23行的代码是不会抛出任何异常的 23 24 try 25 { 26 str = br.readLine(); //会抛出IOException异常 27 } 28 catch (IOException e) 29 { 30 e.printStackTrace(); 31 System.exit(-1); 32 } 33 34 System.out.println("str = " + str); 35 try 36 { 37 br.close(); //会抛出IOException异常 38 } 39 catch (IOException e) 40 { 41 e.printStackTrace(); 42 System.exit(-1); 43 } 44 } 45 } 46 /* 47 在JDK 1.6中的运行结果是: 48 -------------------------------- 49 sadd行政村123Asd?asd撒旦 50 str = sadd行政村123Asd?asd撒旦 51 -------------------------------- 52 */
readLine()与回车符的问题:
Print流 PrintWriter PrintStream
Print 流只有输出,没有输入
分类:
PrintWriter输入字符
PrintStream输出字符
PrintWriter在OutputStream基础之上提供了增强的功能,既可以方便地输出各种类型数据(而不仅限于byte型)的格式化表示形式。
PrintStream重载了print和println方法,用于各种不同类型数据的格式化输出。
格式化输出是指将一个数据用其字符串格式输出。
DataOutputStream 中的 WriteXXX(data)方法是把data在内存中的二进制数据写入文件
PrintStream 中的println(data)是该数据格式化后的字符串写入文件
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /* 2 DataOutputStream 中的 writeXXX(data)方法 3 与 4 PrintStream 中的 println(data)的区别 5 6 总结: 7 DataOutputStream 中的 writeXXX(data)方法是把data在内存中的二进制数据写入文件 8 PrintStream 中的 println(data)写出的是该数据的格式化后的字符串 9 */ 10 11 import java.io.*; 12 13 public class TestPrintStream_1 14 { 15 public static void main(String[] args) throws Exception 16 { 17 DataOutputStream dos = new DataOutputStream(new FileOutputStream("d:/share/kk.txt")); 18 dos.writeLong(12345); //实际写入文件的是00 00 00 00 00 00 30 39 19 dos.close(); 20 System.out.printf("%#X\n", 12345); 21 22 PrintStream ps = new PrintStream(new FileOutputStream("d:/share/kk2.txt"), true); 23 ps.println(12345); //实际写入文件的是'1' '2' '3' '4' '5' 24 ps.close(); 25 } 26 }
PrintWriter 提供了PrintStream的所有打印方法, 其方法也从不抛出IOException。
与PrintStream的区别:
标准输入输出的重定向:
实例:编程实现将键盘输入的数据输入A文件中,如果输入有误,则把出错信息输出到B文件
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 import java.io.*; 2 3 public class TestSetSystemOut { 4 public static void main(String[] args) { 5 PrintStream ps_out = null; 6 7 try { 8 ps_out = new PrintStream(new FileOutputStream("d:/share/ww.txt")); 9 System.setOut(ps_out); // 将System.out的值重新设置为ps_out,即System.out不在关联到显示器,而是关联到"d:/share/ww.txt"文件 10 System.out.println(12); // 这实际上是把12输出到了System.out所关联的d:/share/ww.txt中 11 System.out.println(55.5); // 同上 12 } catch (Exception e) { 13 e.printStackTrace(); 14 } finally { 15 try { 16 ps_out.close(); 17 } catch (Exception e) { 18 e.printStackTrace(); 19 } 20 21 } 22 } 23 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /* 2 功能: 将键盘输入的数据输入A文件中,如果输入有误, 3 则把出错信息输出到B文件中 4 5 标准输入输出流的重定向 6 */ 7 8 import java.io.*; 9 import java.util.*; 10 11 public class TestSetOutErr { 12 public static void main(String[] args) { 13 PrintStream psOut = null; 14 PrintStream psError = null; 15 Scanner sc = null; 16 17 try { 18 psOut = new PrintStream("d:/Out.txt"); 19 psError = new PrintStream("d:/error.txt"); 20 sc = new Scanner(System.in); 21 int num; 22 System.setOut(psOut); 23 System.setErr(psError); 24 25 while (true) { 26 num = sc.nextInt(); 27 System.out.println(num); 28 } 29 } catch (Exception e) { 30 System.err.println("出错的信息是:"); // 不可以写成System.out.println("出错的信息是:"); 31 e.printStackTrace(); // e.printStackTrace(); 默认是输出到System.err所关联的设备中 32 } 33 } 34 }
![](https://i-blog.csdnimg.cn/blog_migrate/6921dd442791b07f104d8cb33275fdc6.png)
实例:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 import java.io.*; 2 3 public class TestObjectIO 4 { 5 public static void main(String[] args) 6 { 7 ObjectOutputStream oos = null; 8 ObjectInputStream ois = null; 9 Student ss = new Student("zhansan", 1000, 88.8f); //注意88.8f不能改为88.8 10 Student ss2 = null; 11 12 try 13 { 14 FileOutputStream fos = new FileOutputStream("d:/share/java/ObjectOut.txt"); 15 oos = new ObjectOutputStream(fos); 16 oos.writeObject(ss); 17 18 ois = new ObjectInputStream(new FileInputStream("d:/share/java/ObjectOut.txt")); 19 ss2 = (Student)ois.readObject(); //(Student)不能省 ois.readObject();如果ois中的某个成员是transient,则该成员是不会被读取的,因为该成员不会被保存,何来读取之说?! 20 21 System.out.println("ss2.sname = " + ss2.sname); 22 System.out.println("ss2.sid = " + ss2.sid); 23 System.out.println("ss2.sscore = " + ss2.sscore); 24 } 25 catch (FileNotFoundException e) 26 { 27 System.out.println("文件没有找到!"); 28 System.exit(-1); 29 } 30 catch (Exception e) 31 { 32 e.printStackTrace(); 33 System.exit(-1); 34 } 35 finally 36 { 37 try 38 { 39 oos.close(); 40 ois.close(); 41 } 42 catch (Exception e) 43 { 44 e.printStackTrace(); 45 System.exit(-1); 46 } 47 } 48 } 49 } 50 51 class Student implements Serializable //如果将implements Serializable 注释掉,则程序编译时就会报错 52 { 53 public String sname = null; 54 public int sid = 0; 55 transient public float sscore = 0; //表示sscore成员不能被序列化,所谓不能被序列化就是指:“该成员调用ObjectOutputStream 的writeOnbject()时不会被保存,调用ObjectInputStream的readObject()方法时不会被读取” 56 57 public Student(String name, int id, float score) 58 { 59 this.sname = name; 60 this.sid = id; 61 this.sscore = score; 62 } 63 }