黑马程序员技术交流社区
标题: 【阳哥笔记】极速秒杀Java基础之笔记系列—Day24( IO )! [打印本页]
作者: 阳哥忠粉 时间: 2015-6-7 22:44
标题: 【阳哥笔记】极速秒杀Java基础之笔记系列—Day24( IO )!
8、IO
8.2 IO流
8.2.11 IO包中的其他类
需求:文件切割器。
代码:
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.util.Properties;
- public class SplitFileDemo{
- private static final int SIZE = 1024*1024;
-
- public static void main(String[] args) throws IOException{
- File file = new File("0.mp3" );
- splitFile(file);
- }
- public static void splitFile(File file) throws IOException {
- //用读取流关联源文件
- FileInputStream fis = new FileInputStream(file);
- //定义一个1M的缓冲区
- byte[] buf = new byte[SIZE];
-
- //创建目的
- FileOutputStream fos = null;
-
- int len = 0;
- int count = 1;
- //切割文件时,必须记录住被切割文件的名称,以及切割出来碎片文件的个数,以方便于合并。
- //这个信息为了进行描述,使用键值对的方式,用到了properties对象。
- Properties prop = new Properties();
- File dir = new File("c:\\partFiles" );
- if(!dir.exists())
- dir.mkdirs();
- while((len = fis.read(buf)) != -1){
- fos = new FileOutputStream(new File(dir,(count++) + ".part"));
- fos.write(buf,0,len);
- fos.close();
- }
-
- //将被切割文件的信息保存到prop集合中
- prop.setProperty( "partcount",count + "" );
- prop.setProperty( "filename",file.getName());
- fos = new FileOutputStream(new File(dir,count + ".properties" ));
-
- //将prop集合中的数据存储到文件中
- prop.store(fos, "save file info");
- fis.close();
- fos.close();
- }
- }
复制代码 运行结果:
需求:文件合并器。
代码:
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.FilenameFilter;
- import java.io.IOException;
- import java.io.SequenceInputStream;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Enumeration;
- import java.util.Iterator;
- import java.util.Properties;
- public class MergeFile{
- public static void main(String[] args) throws IOException {
- File dir = new File("c:\\partFiles" );
- mergeFile(dir);
- }
- public static void mergeFile(File dir) throws IOException {
- //获取指定目录下的配置文件对象
- File[] files = dir.listFiles( new SuffixFilter(".properties" ));
-
- if(files.length!=1)
- throw new RuntimeException(dir + ",该目录下没有properties扩展名的文件或者不唯一" );
-
- //记录配置文件对象
- File confile = files[0];
- //获取该文件中的信息
- Properties prop = new Properties();
- FileInputStream fis = new FileInputStream(confile);
- prop.load(fis);
- String filename = prop.getProperty( "filename");
- int count = Integer.parseInt(prop.getProperty("partcount"));
-
- //获取该目录下的所有碎片文件
- File[] partFiles = dir.listFiles( new SuffixFilter(".part" ));
- if(partFiles.length != (count - 1)){
- throw new RuntimeException("碎片文件不符合要求,个数不对!应该是" + count + "个");
- }
-
- //将碎片文件和流对象关联并存储到集合中
- ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
- for(int x = 1; x <= partFiles.length; x++){
- al.add( new FileInputStream(partFiles[x-1]));
- }
- final Iterator<FileInputStream> it = al.iterator();
-
- //将多个流合并成一个序列流
- Enumeration<FileInputStream> en = Collections.enumeration(al);
- SequenceInputStream sis = new SequenceInputStream(en);
- FileOutputStream fos = new FileOutputStream(new File(dir,filename));
- byte[] buf = new byte[1024*1024];
-
- int len = 0;
- while((len = sis.read(buf)) != -1){
- fos.write(buf,0,len);
- }
- fos.close();
- sis.close();
- }
- }
- class SuffixFilter implements FilenameFilter{
- private String suffix;
- public SuffixFilter(String suffix){
- super();
- this.suffix = suffix;
- }
- public boolean accept(File dir,String name){
- return name.endsWith(suffix);
- }
- }
复制代码 运行结果:
操作对象
ObjectInputStream与ObjectOutputStream
P.S.
被操作的对象需要实现Serializable。
类通过实现java.io.Serializable接口以启用序列化功能,Serializable只是一个标记接口。
示例1:
- import java.io.Serializable;
- class Person implements Serializable{
- 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;
- }
- }
复制代码 运行结果:
示例2:
- import java.io.FileInputStream;
- import java.io.ObjectInputStream;
- public class ObjectStreamDemo{
- public static void main(String[] args) throws Exception {
- readObj();
- }
- public static void readObj() throws Exception {
- ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.object" ));
-
- Person p = (Person)ois.readObject();
- System.out.println(p.getName() + ":" + p.getAge());
- ois.close();
- }
- }
复制代码 运行结果: 如果修改Person类中属性的修饰符为public,就会报如下异常。
原因分析:
Serializable:用于给被序列化的类加入ID号,用于判断类和对象是否是同一个版本。
API解释如下:
为Person类添加序列号属性。此时,再将Person类中属性修饰符修改为public,也不会出现任何异常。
- class Person implements Serializable{
- private static final long serialVersionUID = 9527;
- public String name ;
- public 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;
- }
- }
复制代码
writeObject方法不能写入类及其所有超类型的瞬态和静态字段的值。
示例3: - import java.io.Serializable;
- class Person implements Serializable{
- private static final long serialVersionUID = 9527;
- private transient String name;
- private static 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;
- }
- }
复制代码 运行结果:
RandomAccessFile
随机访问文件,自身具备读写的方法。
通过skipBytes(int x),seek(int x)等方法来达到随机访问。
特点:
1. 该对象即能读,又能写。
2. 该对象内部维护了一个byte数组,并通过指针可以操作数组中的元素。
3. 可以通过getFilePointer方法获取指针的位置,和通过seek方法设置指针的位置。
4. 其实该对象就是将字节输入流和输出流进行了封装。
5. 该对象的源或者目的只能是文件。通过构造函数就可以看出。
P.S.
RandomAccessFile不是io体系中的子类。
示例1:
- import java.io.IOException;
- import java.io.RandomAccessFile;
- public class RandomAccessFileDemo{
- public static void main(String[] args) throws IOException {
- writeFile();
- }
- //使用RandomAccessFile对象写入一些人员信息,比如姓名和年龄
- public static void writeFile() throws IOException {
- //如果文件不存在,则创建,如果文件存在,不创建
- RandomAccessFile raf = new RandomAccessFile("ranacc.txt" ,"rw" );
-
- raf.write( "张三".getBytes());
- //使用write方法之写入最后一个字节
- raf.write(97);
- //使用writeInt方法写入四个字节(int类型)
- raf.writeInt(97);
-
- raf.write( "小强".getBytes());
- raf.writeInt(99);
- raf.close();
- }
- }
复制代码 运行结果:
示例2:
- import java.io.IOException;
- import java.io.RandomAccessFile;
- public class RandomAccessFileDemo{
- public static void main(String[] args) throws IOException {
- readFile();
- }
- public static void readFile() throws IOException {
- RandomAccessFile raf = new RandomAccessFile("ranacc.txt" ,"r" );
-
- //通过seek设置指针的位置
- raf.seek(9); //随机的读取,只要指定指针的位置即可
- byte[] buf = new byte[4];
- raf.read(buf);
- String name = new String(buf);
- System.out.println( "name=" + name);
- int age = raf.readInt();
- System.out.println( "age=" + age);
- System.out.println( "pos:" + raf.getFilePointer());
- raf.close();
- }
- }
复制代码 运行结果:
示例3:
- import java.io.IOException;
- import java.io.RandomAccessFile;
- public class RandomAccessFileDemo{
- public static void main(String[] args) throws IOException {
- randomWrite();
- }
- public static void randomWrite() throws IOException {
- RandomAccessFile raf = new RandomAccessFile("ranacc.txt" ,"rw" );
-
- //往指定位置写入数据
- raf.seek(3*8);
-
- raf.write( "哈哈".getBytes());
- raf.writeInt(102);
- raf.close();
- }
- }
复制代码 运行结果:
管道流
PipedInputStream和PipedOutputStream:输入输出可以直接进行连接,通过结合线程使用。
示例1:
- import java.io.PipedInputStream;
- import java.io.PipedOutputStream;
- public class PipedStream{
- public static void main(String[] args) throws Exception {
- PipedInputStream input = new PipedInputStream();
- PipedOutputStream output = new PipedOutputStream();
- input.connect(output);
- new Thread(new Input(input)).start();
- new Thread(new Output(output)).start();
- }
- }
- class Input implements Runnable{
- private PipedInputStream in;
-
- Input(PipedInputStream in){
- this.in = in;
- }
- public void run(){
- try{
- byte[] buf = new byte[1024];
- int len = in.read(buf);
- String s = new String(buf,0,len);
- System.out.println( "s=" + s);
- in.close();
- } catch(Exception e){
- e.printStackTrace();
- }
- }
- }
- class Output implements Runnable{
- private PipedOutputStream out;
-
- Output(PipedOutputStream out){
- this.out = out;
- }
- public void run(){
- try{
- out.write( "hi,管道来了!" .getBytes());
- out.close();
- } catch(Exception e){
- e.printStackTrace();
- }
- }
- }
复制代码 运行结果:
操作基本数据类型
DataInputStream与DataOutputStream
示例1:
- import java.io.DataOutputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- public class DataStreamDemo{
- public static void main(String[] args) throws IOException {
- writeData();
- }
- public static void writeData() throws IOException {
- DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt" ));
-
- dos.writeUTF( "您好");
- dos.close();
- }
- }
复制代码 运行结果:
示例2:
- import java.io.DataInputStream;
- import java.io.FileInputStream;
- import java.io.IOException;
- public class DataStreamDemo{
- public static void main(String[] args) throws IOException {
- readData();
- }
- public static void readData() throws IOException {
- DataInputStream dis = new DataInputStream(new FileInputStream("data.txt" ));
-
- String str = dis.readUTF();
-
- System.out.println(str);
- dis.close();
- }
- }
复制代码 运行结果:
操作字节数组
ByteArrayInputStream与ByteArrayOutputStream
P.S.
关闭字节数组输出输出流无效,因为它们没有调用底层资源,所有的操作都是在内存中完成的。
示例1:
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- public class ByteArrayStreamDemo{
- public static void main(String[] args) throws IOException {
- ByteArrayInputStream bis = new ByteArrayInputStream("abcdef" .getBytes());
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- int ch = 0;
- while((ch = bis.read()) != -1){
- bos.write(ch);
- }
- System.out.println(bos.toString());
- }
- }
复制代码 运行结果:
编码表的由来
计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。
就将各个国家的文字用数字来表示,并一一对应,形成一张表,这就是编码表。
常见的编码表
ASCII:美国标准信息交换码,用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表,用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
Unicode:国际标准码,融合了多种文字。
所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符。
......
示例1:
- import java.io.IOException;
- public class EncodeDemo{
- public static void main(String[] args) throws IOException{
- //字符串-->字节数组:编码
- //字符数组-->字符串:解码
- String str = "您好";
- //编码
- byte[] buf1 = str.getBytes("GBK" );
- printBytes(buf1);
- byte[] buf2 = str.getBytes("UTF-8" );
- printBytes(buf2);
- //解码
- String s1 = new String(buf1);
- System.out.println( "s1 = " + s1);
- String s2 = new String(buf2,"UTF-8" );
- System.out.println( "s2 = " + s2);
- }
- private static void printBytes(byte[] buf){
- for(byte b : buf){
- System.out.print(b + " ");
- }
- System.out.println();
- }
- }
复制代码 运行结果: 如果编码编错了,解不出来。
如果编对了,解错了,有可能有救。
示例2:
- import java.io.IOException;
- public class EncodeDemo{
- public static void main(String[] args) throws IOException{
- String str = "您好";
-
- byte[] buf = str.getBytes("gbk" );
- String s1 = new String(buf,"iso8859-1" );
- System.out.println( "s1 = " + s1);
- byte[] buf2 = s1.getBytes("iso8859-1" );
- String s2 = new String(buf2,"gbk" );
- System.out.println(s2);
- }
- private static void printBytes(byte[] buf){
- for(byte b : buf){
- System.out.println(b);
- }
- }
- }
复制代码 运行结果:
如果编对了,解错了,也可能没救了。
示例3:
- import java.io.IOException;
- public class EncodeDemo{
- public static void main(String[] args) throws IOException{
- String str = "您好";
-
- byte[] buf = str.getBytes("gbk" );
- String s1 = new String(buf,"UTF-8" );
- System.out.println( "s1 = " + s1);
- byte[] buf2 = s1.getBytes("UTF-8" );
-
- printBytes(buf2);
- String s2 = new String(buf2,"gbk" );
- System.out.println(s2);
- }
- private static void printBytes(byte[] buf){
- for(byte b : buf){
- System.out.print(b + " ");
- }
- System.out.println();
- }
- }
复制代码 运行结果:
原因分析:
“您好”的gbk编码在UTF-8码表中查不到对应的字符,所以已经用“?”代替。
“?”在UTF-8中的编码为-17 -65 -67
故即使使用UTF-8码表进行解码,获取的字节也不是“您好”的gbk编码后的字节。
所以再也不能成功解码了。
P.S.
“谢谢”的gbk编码在UTF-8码表中可以查到对应的字符,为“ππ”。
因此,使用UTF-8码表对“ππ”进行解码,获取的字节也依然是“您好”的gbk编码后的字节。
所以,不会出现“您好”发生的情况。
实验:联通乱码问题。
步骤:
1. 新建一个1.txt文件。
2. 输入联通,保存。
3. 关闭,重新打开此文件,发现乱码。
原因分析:
“联通”经过gbk编码后成四个字节:11000001、10101010、11001101、10101000。
正好符合UTF-8的编码规则。所以,记事本按照UTF-8进行了解码,从而出现了乱码现象。
练习:
在java中,字符串“abcd”与字符串“ab您好”的长度是一样,都是四个字符。
但对应的字节数不同,一个汉字占两个字节。
定义一个方法,按照最大的字节数来取子串。
如:对于“ab你好”,如果取三个字节,那么子串就是ab与“你”字的半个。
那么半个就要舍弃。如果取四个字节就是“ab你”,取五个字节还是“ab你”。
代码:
- import java.io.IOException;
- public class Test{
- public static void main(String[] args) throws IOException {
- String str = "ab你好cd谢谢" ;
- int len = str.getBytes("gbk" ).length;
- for(int x = 1; x < len; x++){
- System.out.println( "截取的" + (x + 1) + "个节结果是:" + cutStringByByte(str,x+1));
- }
- }
- public static String cutStringByByte(String str,int len) throws IOException {
- byte[] buf = str.getBytes("gbk" );
- int count = 0;
- for(int x = len - 1; x >= 0; x--){
- //gbk编码的值两个字节值一般都为负,记录连续的负数个数,如果为奇数,则舍弃
- if(buf[x] < 0)
- count++;
- else
- break;
- }
- if(count % 2 == 0){
- return new String(buf,0,len,"gbk");
- } else{
- return new String(buf,0,len-1,"gbk");
- }
- }
- }
复制代码 运行结果:
P.S.
中文经过gbk编码后,也有两个字节不都为负数的情况,例如“琲”,字节值为-84、105。
第一个字节值为负,第二个字节值为正。因此,上面的代码得出的结果依然正确。
定义一个方法,按照最大的字节数来取子串,使用UTF-8编码的代码如下:
代码:
- public class Test{
- public static void main(String[] args) throws Exception {
- String str = "ab你好cd谢谢" ;
- int len = str.getBytes("utf-8" ).length;
- for(int x = 1; x < len; x++){
- System.out.println( "截取的" + (x + 1) + "个节结果是:" + cutStringByByte(str,x+1));
- }
- }
- public static String cutStringByByte(String str,int len) throws Exception {
- byte[] buf = str.getBytes("utf-8" );
- int count = 0;
- for(int x = len - 1; x >= 0; x--){
- if(buf[x] < 0)
- count++;
- else
- break;
- }
- if(count % 3 == 0)
- return new String(buf,0,len,"utf-8");
- else if (count % 3 == 1)
- return new String(buf,0,len-1,"utf-8");
- else
- return new String(buf,0,len-2,"utf-8");
- }
- }
复制代码 运行结果:
~END~
作者: itheima_llt 时间: 2015-6-7 22:57
好快啊!顶一下!
作者: 灵界 时间: 2015-6-7 22:59
更新好快,支持
作者: cyd1058 时间: 2015-6-8 21:18
给力!!!!!!!!
作者: cyd1058 时间: 2015-6-8 21:20
更新很快!很赞!
作者: SouthKai 时间: 2015-6-8 21:55
阳哥给力啊,这么快!
作者: 流水0215 时间: 2015-6-9 09:21
阳哥辛苦了
作者: 新缘 时间: 2015-6-9 18:30
赞一个。
作者: 熊乾坤 时间: 2015-6-9 22:17
赞!赞!赞!赞!赞!赞!
作者: cyd1058 时间: 2015-6-9 22:46
更新很快!!辛苦了
作者: 魏海洲 时间: 2015-6-11 19:10
阳哥给力啊,这么快
作者: richaled 时间: 2015-6-13 10:07
给力,更新的很快
作者: libin159028 时间: 2015-6-15 00:14
z赞 好详细
作者: 魏海洲 时间: 2015-6-16 21:15
好快啊!顶一下!
作者: wenweishan2015 时间: 2015-6-17 01:08
赞一个!!!
作者: 新缘 时间: 2015-6-18 19:33
:):):):):):)
作者: 魏海洲 时间: 2015-6-22 21:33
好快啊!顶一下!
作者: 绝版坏银 时间: 2015-6-25 16:27
今天的好难记啊。- -。回想一遍朦朦胧胧,貌似什么都没记住
作者: wanghua1 时间: 2015-7-8 00:13
点个赞!!!
作者: 星痕-凌 时间: 2015-7-12 17:25
阳哥,太牛,好赞 !!!!!!!!!!!!!!!!赞
作者: 星痕-凌 时间: 2015-7-14 22:00
笔记比较仔细,很不错!!!!!!!!!!!!!!!!!!
作者: 星痕-凌 时间: 2015-7-16 22:07
还没学到,先下载下来,学到看!!!!!!!!!
作者: 星痕-凌 时间: 2015-7-18 21:04
很不错,努力学好!!!!!!!!!!!!!!!!!!!!!!!!!!!
作者: xyxlx111 时间: 2015-7-18 23:58
写的不错,顶一个
作者: heima_cy 时间: 2015-8-14 17:00
已经自学一个月了 感谢分享
作者: qq100511544 时间: 2015-8-18 00:39




作者: 七了个七 时间: 2015-8-18 09:10
赞赞赞呀
作者: pengbeilin 时间: 2015-8-18 11:36
斯国一~
作者: 风华正茂 时间: 2015-8-18 12:14
谢谢阳哥分享
作者: 漠陌 时间: 2015-8-18 12:43
感谢分享
作者: qq100511544 时间: 2015-8-22 09:28
马上学到 IO 流了~~貌似有点难啊~@@
作者: qq100511544 时间: 2015-8-23 00:17
阳哥威武!!
作者: chensheng06 时间: 2015-8-23 07:05
好贴 帮助查漏补缺
作者: a1ccwt 时间: 2015-8-23 08:13
写的好专业
作者: koibiki 时间: 2015-8-23 11:02
总结得很好
作者: Yan_Theo 时间: 2015-10-2 01:11
欢天喜地来盖楼。
作者: chenwt2015 时间: 2015-10-2 01:54
阳哥你真帅!
作者: Yan_Theo 时间: 2015-10-2 13:19
继续加油
作者: Smilexs 时间: 2015-10-3 10:58
学习了学习了。
作者: 如梦丶似幻 时间: 2015-10-3 22:16
前来学习~~~~~
作者: 101350 时间: 2015-10-21 19:31



作者: 爨oooo 时间: 2015-10-21 22:02
看不懂....
作者: 爨oooo 时间: 2015-10-21 22:59
顶一下~~留着以后看
作者: yqlbd 时间: 2015-11-21 22:26
先顶再看,谢谢。
作者: lktz 时间: 2016-2-16 01:39
标记一下
作者: 一真 时间: 2016-2-17 22:47
辛苦了,谢谢啦
作者: 13120298870 时间: 2016-5-13 23:17
阳哥!!!!!!!!!!
有没有mysql的讲解内容?????、
求MySQL 知识点。。。
| 欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |