JavaSE-IO输入输出-装饰设计模式

JAVA-IO

早期IO都是对字节流的操作,但是为了方便操作文本后来出现了字符流。

  1. ASCII-英文

  2. GB1312-中文(不够)

  3. GBK-中文(扩容)

  4. Unicode(无论什么字符都用两位字节) -万国码

  5. UTF-8(字节优化)-万国码

为了解决乱码问题,JAVA提供字符流,只需要设置码表即可正常查阅数据。

01 FileWriter

基本写入数据

/**
* FileWriter的父类是Writer
* FileWriter中没有方法,只有构造当需要写入操作时:调用父类的write();
* FileWriter:覆盖原文件,不管有没有都会自动创建
* 调用write()方法会把数据放入缓冲区
* 调用flush()方法会刷新缓冲区,吸入目的地
* 调用close()也会刷新缓冲区,但是关闭了流,继续写入会抛异常
*/

FileWriter fileWriter = new FileWriter("D:\\ok.txt");
fileWriter.write("嘿嘿");
fileWriter.flush();

在文件尾部追加

new FileWriter("path",true);//即可追加在文件末尾

02 FileReader

  • int read();//读取的数据,没有时为-1
FileReader fileReader = new FileReader("D:\\ok.txt");
int data = 0;
while ((data=fileReader.read())!=-1){
    System.out.println((char)data);
}
  • int read(char [] c);//返回读取的个数,没有就是-1
FileReader fileReader = new FileReader("D:\\ok.txt");
char c[] = new char[4];
int len = 0;
while ((len=fileReader.read(c))!=-1){
    System.out.println(len);
    System.out.println(c);
}
//运行结果:
4
abcd
2
efcd

new String(char[],start,lenth);

FileReader fileReader = new FileReader("D:\\ok.txt");
char c[] = new char[4];
int len = 0;
while ((len=fileReader.read(c))!=-1){
    System.out.println(len);
    System.out.println(new String(c,0,len));
}
//运行结果:
4
abcd
2
ef

03 BufferedWriter

缓冲区的出现是为了提高效率

FileWriter fileWriter = new FileWriter("D:\\ok.txt");
//其内部其实就是为FileWriter对象进行了
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
for (int i = 0; i < 10; i++) {
    bufferedWriter.write("abcdef"+i);
    //不同的操作系统不同的换行符
    bufferedWriter.newLine();
}
//其实就是对FileWriter进行关闭操作
bufferedWriter.close();

04 BufferedReader

FileReader fileReader = new FileReader("D:\\ok.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line = "";
/**
*bufferedReader.readLine()
*只返回有效数据内容,并不返回回车等终止符
*其原理就在于:遇到\n就返回字符数组,遇到\r就continue,将字符装入数组
*/
while ((line = bufferedReader.readLine())!=null) {
    System.out.println(line);
}
bufferedReader.close();//其实就是对fileReader进行关闭

05 LineNumberReader

这两个类都相当于是装饰类,和BufferedReader、BufferedWriter一样,只不过增加了设置行数和获取行数

06 LineNumberWriter

在FileReader的基础上,装饰扩展出读取一行数据的功能,并且可以设置初始行号和读取到的当前行号

  • setLineNumber(int l);
  • getLineNumber();

07 装饰设计模式

增强已有的对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰类都属于一个体系

最经典的例子就是BufferedWriter与FileWriter的设计关系:

  • BufferedWriter其实是对FileWriter对象的功能增强,增加了使用数组做缓冲区,一次性写入的高效方法,其原理就是通过构造器传入FileWriter对象,在其功能的基础上进行功能扩展。

  • BufferedWriter的构造器只能传入Writer类型,这里之所以使用多态,是为了提高程序的可扩展性,否则如果每次针对一个类似于FileWriter的类型就要增加一种构造器,这样程序的可扩展性极差。

设计方式:

  • 首先你需要使得各个功能类似的类继承同一个基类
  • 那么,装饰类只需要把构造器对这个基类开放即可

装饰模式的优点:

  • 比继承灵活,避免了继承体系的臃肿
  • 降低类与类之间的关系

08 IO异常处理方式

如果有多个IO操作对象,则需要在finally中进行多次独立的if(obj!=null)的判断操作,这才是最标准的异常捕捉!

FileWriter fileWriter = null;
try {
    fileWriter = new FileWriter("D:\\ok.txt");
    fileWriter.write("嘿嘿");
} catch (IOException e) {
    e.printStackTrace();
}finally {
    try {
        if(fileWriter!=null){
            fileWriter.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

快速自定义抛出异常:

在catch块当中:throw new RuntimeException("自定义异常");

09 InputStream

假如有一个文件:

abcde
f

使用FileInputStream读取,获得available()时,其返回值是8!

因为在windows操作系统中,回车"\r\n"占据两个字节,到字节流后变成两个字节

10 OutputStream

FileInputStream fileInputStream = new FileInputStream("path");
FileOutputStream fileOutputStream = new FileOutputStream("path");
byte b[]  = new byte[1024];
int len = 0;
while ((len = fileInputStream.read(b))!=-1){
    fileOutputStream.write(b,0,len);
}
fileInputStream.close();
fileOutputStream.close();

11 BufferedInputStream

装饰FileInputStream的类,用法和字符流相似

12 键盘输入流

在java.lang包下面System类中in是一个被静态InputStream描述的字节读取流对象,out和err是PrintStream对象。

//读取一个字符
String str =  ""+System.in.read();
System.out.println(str);
Scanner scanner = new Scanner(System.in);
int num = scanner.nextInt();
System.out.println(num);

13 转换流

  • InputStreamReader:把输入字节流转换成字符流操作
  • OutputStreamWriter:把输出字节流转换成字符流操作
//字节流输入
InputStream inputStream = System.in;
//输出的的时候操作字符流对象
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
//使用包装类,调用readLine();
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
//读取一行数据,如果输入exit就退出
String line = "";
while (!(line = bufferedReader.readLine()).equals("exit")){
    System.out.println(line);
}
//关闭
bufferedReader.close();

还有一个好玩的装饰类:

//字节流输入
InputStream inputStream = System.in;
//输出的的时候操作字符流对象
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
//使用包装类,调用readLine();
LineNumberReader lineNumberReader = new LineNumberReader(inputStreamReader);
//读取一行数据,如果输入exit就退出
String line = "";
while (!(line = lineNumberReader.readLine()).equals("exit")){
    System.out.println(lineNumberReader.getLineNumber()+":"+line);
}
//关闭
lineNumberReader.close();

14 File

  • boolean createNewFile();//存在文件返回false
  • boolean delete();
  • int compareTo(File f);//字母顺序比较名称
  • boolean exists();
  • boolean mkdir();//创建目录
  • boolean isDirectory();//是否目录
  • boolean isFile();//是否文件
  • boolean isHidden();//是否隐藏
  • String getPath();
  • String getAbsolutePath();
  • long length();

15 Properties

位于 java.util.Properties ,是Java 语言的配置文件所使用的类, Xxx.properties 为Java 语言常见的配置文件,如数据库的配置 jdbc.properties, 系统参数配置 system.properties。 这里,讲解一下Properties 类的具体使用。继承了Hashtable 类,以Map 的形式进行放置值, put(key,value) get(key),以key=value 的 键值对的形式进行存储值。 key值不能重复。

Properties properties=new Properties();
//用绝对路径
InputStream input=new BufferedInputStream(new FileInputStream("D:\\workspace\\JavaLearn\\src\\jdbc.properties"));
properties.load(new InputStreamReader(input,"utf-8"));
//多添加几个值。
properties.setProperty("name","两个蝴蝶飞");
properties.setProperty("sex","男");

OutputStream output=new FileOutputStream("D:\\jdbc.properties");
OutputStreamWriter out=new OutputStreamWriter(output,"utf-8");
properties.store(out,"填充数据");

16 对象序列化

对象持久化存储:找到可长久保存对象的介质,叫做持久化,想要一个对象被序列化,该类必须实现io下的接口:Serializable

标记接口:没有任何方法的接口,例如:Serializable,其原理就是为对象加个UID值,但是也可以自定义一个UID

ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("a.txt"));
objectOutputStream.writeObject(new People("嘿嘿","男"));
objectOutputStream.close();
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("a.txt"));
People people = (People) objectInputStream.readObject();
System.out.println(people.getName()+":"+people.getSex());

17 管道流

import java.io.*;

class MyReader implements Runnable {
    public PipedInputStream pipedInputStream;
    public MyReader(PipedInputStream input){
        this.pipedInputStream = input;
    }
    @Override
    public void run() {
        try {
            byte b[] = new byte[1024];
            int len = pipedInputStream.read(b);
            String str = new String(b,0,len);
            System.out.println(str);
            pipedInputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class MyWriter implements Runnable{
    private PipedOutputStream pipedOutputStream;
    public MyWriter(PipedOutputStream out){
        this.pipedOutputStream = out;
    }
    @Override
    public void run() {
        try {
            Thread.sleep(6000);
            pipedOutputStream.write("我爱你".getBytes());
            pipedOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class Out {
    public static void main(String[] args) throws Exception {
        PipedInputStream pipedInputStream = new PipedInputStream();
        PipedOutputStream pipedOutputStream = new PipedOutputStream();
        MyReader myReader = new MyReader(pipedInputStream);
        MyWriter myWriter = new MyWriter(pipedOutputStream);
        pipedInputStream.connect(pipedOutputStream);//管道流关联
        new Thread(myReader).start();
        new Thread(myWriter).start();
    }
}

18 RandomAccessFile

RandomAccessFile既可以读取文件内容,也可以向文件输出数据。同时,RandomAccessFile支持“随机访问”的方式,程序快可以直接跳转到文件的任意地方来读写数据。

  • 可以自由访问文件的任意位置,所以如果需要访问文件的部分内容,而不是把文件从头读到尾,使用RandomAccessFile将是更好的选择。
  • 允许自由定义文件记录指针(OutputStream、Writer等输出流不同),RandomAccessFile可以不从开始的地方开始输出,因此RandomAccessFile可以向已存在的文件后追加内容。如果程序需要向已存在的文件后追加内容,则应该使用RandomAccessFile。
  • 它有一个最大的局限,就是只能读写文件,不能读写其他IO节点。RandomAccessFile的一个重要使用场景就是网络请求中的多线程下载及断点续传。

四种模式:

**"r" : ** 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
"rw": 打开以便读取和写入。
"rws": 打开以便读取和写入。相对于 "rw","rws" 还要求对“文件的内容”或“元数据”的每个更新都同步写入到基础存储设备。
"rwd" : 打开以便读取和写入,相对于 "rw","rwd" 还要求对“文件的内容”的每个更新都同步写入到基础存储设备。

特殊方法:

long getFilePointer( );//返回文件记录指针的当前位置
void seek(long pos);//将文件指针定位到pos位置

利用RandomAccessFile实现文件的多线程下载,即多线程下载一个文件时,将文件分成几块,每块用不同的线程进行下载。当RandomAccessFile向指定文件中插入内容时,将会覆盖掉原有内容。如果不想覆盖掉,则需要将原有内容先读取出来,然后先把插入内容插入后再把原有内容追加到插入内容后。

下面是一个利用多线程在写文件时的例子,其中预先分配文件所需要的空间,然后在所分配的空间中进行分块,然后写入:

/** 
 * 测试利用多线程进行文件的写操作 
 */  
public class Test {  
  
    public static void main(String[] args) throws Exception {  
        // 预分配文件所占的磁盘空间,磁盘中会创建一个指定大小的文件  
        RandomAccessFile raf = new RandomAccessFile("D://abc.txt", "rw");  
        raf.setLength(1024*1024); // 预分配 1M 的文件空间  
        raf.close();  
          
        // 所要写入的文件内容  
        String s1 = "第一个字符串";  
        String s2 = "第二个字符串";  
        String s3 = "第三个字符串";  
        String s4 = "第四个字符串";  
        String s5 = "第五个字符串";  
          
        // 利用多线程同时写入一个文件  
        new FileWriteThread(1024*1,s1.getBytes()).start(); // 从文件的1024字节之后开始写入数据  
        new FileWriteThread(1024*2,s2.getBytes()).start(); // 从文件的2048字节之后开始写入数据  
        new FileWriteThread(1024*3,s3.getBytes()).start(); // 从文件的3072字节之后开始写入数据  
        new FileWriteThread(1024*4,s4.getBytes()).start(); // 从文件的4096字节之后开始写入数据  
        new FileWriteThread(1024*5,s5.getBytes()).start(); // 从文件的5120字节之后开始写入数据  
    }  
      
    // 利用线程在文件的指定位置写入指定数据  
    static class FileWriteThread extends Thread{  
        private int skip;  
        private byte[] content;  
          
        public FileWriteThread(int skip,byte[] content){  
            this.skip = skip;  
            this.content = content;  
        }  
          
        public void run(){  
            RandomAccessFile raf = null;  
            try {  
                raf = new RandomAccessFile("D://abc.txt", "rw");  
                raf.seek(skip);  
                raf.write(content);  
            } catch (FileNotFoundException e) {  
                e.printStackTrace();  
            } catch (IOException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            } finally {  
                try {  
                    raf.close();  
                } catch (Exception e) {  
                }  
            }  
        }  
    }  
  
}  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容

  • 1 什么是IO? 1 Java的IO机制有流IO和块IO两种,核心库 java.io是大多数面向数据流的IO类的主...
    paulpaullong阅读 442评论 0 1
  • 一.java.io.File类 java.io.File类用于表示文件/目录 File只用于表示文件的信息(名称,...
    liangxifeng833阅读 758评论 0 1
  • 1.流的分类 (1)输入输出流输入输出是针对程序运行的内存而言的输入流的基类:InputStream,Reader...
    ql2012jz阅读 580评论 0 3
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,536评论 28 53
  • 信任包括信任自己和信任他人 很多时候,很多事情,失败、遗憾、错过,源于不自信,不信任他人 觉得自己做不成,别人做不...
    吴氵晃阅读 6,190评论 4 8