您的位置:首页 > 职场人生

黑马程序员--Java基础之IO

2014-11-02 16:28 351 查看
------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流!

Java之IO整理(学到觉得玩一会都有罪恶感,加油)

概述:
IO(Input Output)流
 IO流用来处理设备之间的数据传输
 Java对数据的操作是通过流的方式
 Java用于操作流的对象都在IO包中
 流按操作数据分为两种:字节流与字符流(字符流基于字节流,融合了编码表)
 流按流向分为:输入流,输出流

IO流常用基类
 字节流的抽象基类:InputStream,OutputStream
 字符流的抽象基类:Reader,Writer
 注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。如:InputStream的子类FileInputStream Reader的子类FileReader
抽象类需要子类去实现

java.io包

凡是能和文件相关的流对象都是比较重要的流对象

一、字符流
字符流(全部熟练掌握!):
字符流继承的体系图(详见字符流继承体系简图.png)
字符输出流:
A. FileWriter写入数据
步骤:
A:创建字符输出流对象
B:调用写入数据方法,并刷新缓冲区
C:释放资源

代码体现:
FileWriter fw = new FileWriter("a.txt");

fw.write("hello,io");
fw.flush();

fw.close();

问题?
A:创建字符输出流对象做了几件事情?
a:调用系统功能创建了文件(不需要单独去建立文件了)
b:创建字符输出流对象
c:把字符输出流对象指向创建的文件

B:写数据完毕后,为什么要刷新?
字符流 1字符 = 2字节,文件数据底层单位是字节,而我们现在写入的是字符,
所以它不能直接把数据写入文件而是把字符输出存储到缓冲区里面,而后需要刷新才能写入文件。

C:为什么要close()?
1:让流对象变成垃圾
2:通知系统去释放和文件相关的资源

D:flush()和close()的区别?
flush():只刷新缓冲区,流对象还可以继续使用。
close():先刷新缓冲区,在关闭流对象。流对象不可以继续被使用。
===>拓展问题:难道每次调用方法的时候,都需要刷新吗?或者说,不用刷,直接等到close()来解决,行不行?
    这两种方式都不可取,应用如下方式:
int count = 0;
for (int x = 0; x < 1000000; x++) {
fw.write("hello,林青霞" + x);
if (++count % 10000 == 0) {
fw.flush();
}
}
即:如果每次调用方法都刷新,flush()方法会不断的调入内存,所以效率会很低;如果等到close()来解决,肯定也是不行的,如
果需求过大,会导致缓冲区容纳不下。所以应该根据需求的规模来设置合适的刷新间隔值,然后每隔此值之后刷新一次,这样既可
以提高效率,又可以避免缓冲区容纳不下等问题。

E:怎么实现数据换行?
给出换行符
windows:\r\n
linu:\n
mac:\r

F:怎么实现数据追加写入?(详见FileWriterDemo3.java)
构造时用带两个参数的
public FileWriter(String fileName,true){}

B. FileReader读取数据(详见FileReaderDemo.java)
步骤:
A:创建字符输入流对象
B:调用读取数据方法,并显示
C:释放资源

代码体现:
FileReader fr = new FileReader("a.txt");

//方式1
//一次读取一个字符
int ch = 0;
while((ch=fr.read())!=-1)
{
System.out.print((char)ch);
}

//方式2
//一次读取一个字符数组
char[] chs = new char[1024];
int len = 0;
while((len=fr.read(chs))!=-1)   //len表示读取到的字符数
{
System.out.print(new String(chs,0,len));
}

fr.close();
二、字节流
字节流基本体系。
1.通过字节流往文件中写数据。
字节输出流操作步骤。(详见FileOutputStreamDemo.java)
* A:创建字节输出流对象,FileOutputStream
* B:调用写数据的方法
* C:释放资源

字节输入流操作步骤。(详见FileInputStreamDemo2.java)
* A:创建字节输入流对象,FileInputStream
* B:调用读取数据的方式,并显示
* C:释放资源
2.带缓冲区的流。(详见BufferedWriterDemo.java)
字符缓冲流读取数据。(详见BufferedReaderDemo.java)

(重要代码!)A.用字符高效流复制文本文件。(详见CopyFile.java)

   B. 把d:\\哥有老婆.mp4复制到项目路径下x.mp3(x=1,2,3,4)。多种方法效率的对比。(详见CopyMP3.java)

   C. 在ArrayList里面存储了3个字符串元素,请把这三个元素写入文本文件。并在每个元素后面加入换行。两种方式。
  (详见ArrayListDemo.java 及 ArrayListDemo2.java)

   D.键盘录入数据写入文本文件。(详见ScannerDemo.java)

   E.将d:\java目录下的所有.java文件复制到d:\jad目录下,并将原来文件的扩展名从.java改为.jad。两种方式。较难!
   (详见CopyFolder.java 及 CopyFolder2.java)

3.字符缓冲流的特殊功能。(详见BufferedStreamDemo2.java 及 CopyFile2.java)

三、读取键盘录入&读取、写入转换流
读取键盘录入  自己必须写一遍!!!!

/*
System.out:对应的是标准输出设备,控制台
System.in:对应的是标准输入设备,键盘

需求:
通过键盘录入数据
当录入一行数据后,就将该行数据进行打印
如果录入的数据是over,那么停止录入
*/
import java.io.*;
class  ReadIn
{
public static void main(String[] args) throws IOException
{
InputStream in = System.in;

StringBuilder sb = new StringBuilder();//用来存放输入的数据

while (true)
{
int ch = in.read();
if(ch=='\r')
continue;
if (ch=='\n')
{
String s = sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
sb.delete(0,sb.length());//应该在打印一次结束后清空
}
else
sb.append((char)ch);
}
}
}

上面的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。也就是readLine方法。
能不能直接使用readLine方法来完成键盘录入一行数据的读取呢?

readLine方法是字符流BufferedReader类中的方法,而键盘录入的read方法是字节流InputStream的方法。
那么能不能将字节流转成字符流再使用字符流缓冲区的readLine方法呢?

读取转换流 InputStreamReader 字节流通向字符流的桥梁

import java.io.*;

class TransStreamDemo 
{
public static void main(String[] args) throws IOException
{
//获取键盘录入对象
InputStream in = System.in;

//将字节流对象转成字符流对象,使用转换流 InputStreamReader
InputStreamReader isr = new InputStreamReader(in);

//为了提高效率,将字符串进行缓冲区技术高效操作,使用 BufferedReader
BufferedReader bufr = new BufferedReader(isr);

String line = null;
while ((line = bufr.readLine())!=null)
{
if("over".equals(line))
break;
System.out.println(line.toUpperCase());
}

bufr.close();
}
}

写入转换流 OutputStreamWriter 字符流通向字节流的桥梁

import java.io.*;

class TransStreamDemo 
{
public static void main(String[] args) throws IOException
{
//InputStream in = System.in;
//InputStreamReader isr = new InputStreamReader(in);
//BufferedReader bufr = new BufferedReader(isr);
//上面三句可简写为:键盘录入的最常见写法    必须记住!!!!!!!!
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

//OutputStream out = System.out;
//OutputStreamWriter osw = new OutputStreamWriter(out);
//BufferedWriter bufw = new BufferedWriter(osw);
//上面三句可简写为:
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

String line = null;
while ((line = bufr.readLine())!=null)
{
if("over".equals(line))
break;
//System.out.println(line.toUpperCase());被替代
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}

bufr.close();
}
}
四、流操作规律
1.之前的输入输出:
源:键盘录入
目的:控制台

2.需求:想把键盘录入的数据存储到一个文件中
源:键盘
目的:文件
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt")));

3.需求:想要将一个文件的数据打印在控制台上
源:文件
目的:控制台
BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("copyPic.java")));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

流操作的基本规律:!!!!!!!!!!!!!!!!!!!
最痛苦的就是流对象有很多,不知道该用哪个

通过三个明确来完成:
1.明确源和目的
源:输入流   InputStream   Reader
目的:输出流 OutputStream  Writer
2.操作的数据是否是纯文本
是:字符流
否:字节流
3.当体系明确后,再明确要使用哪个具体的对象
通过设备来进行区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台

具体问题分析:
1.将一个文本文件中的数据存储到另一个文件中,即复制文件
源:因为是源,所以使用读取流:InputStream Reader 
   是不是操作文本文件?是!所以选择Reader。这样体系就明确了。
   接下来明确要使用该体系中哪个对象。
   明确设备:硬盘  硬盘上的一个文件
   Reader体系中可以操作文件的对象是FileReader

FileReader fr = new FileWriter("a.txt");

   是否需要提高效率?是! 加入Reader体系中的BufferedReader
BufferedReader bufr = new BufferedReader(fr);

目的:OutputStream  Writer
   是否为纯文本?是!选择Writer
   明确设备:硬盘
   Writer体系中可以操作文件的对象是FileWriter

FileWriter fw = new FileWriter("b.txt");

   是否需要提高效率? 是! 加入Writer体系中的BufferedWriter
BufferedWriter bufw = new BufferedWriter(fw);
练习:将一个图片文件存储到另一个文件中。复制文件。要求按照以上格式完成三个明确

2.需求:将键盘录入的数据保存到一个文件中
 分析:源和目的都存在。
源:InputStream Reader 
   是不是纯文本?是!所以选择Reader。这样体系就明确了。
   设备:键盘。对应的对象是System.in
   不是选择了Reader吗?System.in对应的不是字节流吗?
   为了操作键盘的文本数据方便,转成字符流按照字符串操作是最方便的。所以既然明确了Reader,那么就将System.in转换成Reader。
   用到了Reader体系中的转换流InputStreamReader

InputStreamReader isr = new InputStreamReader(System.in);

   需要提高效率吗?需要! BufferedReader
BufferedReader bufr = new BufferedReader(isr);

目的:OutputStream Writer
   是不是纯文本?是!Writer
   设备:硬盘  一个文件 使用FileWriter

FileWriter fw = new FileWriter("c.txt");

   需要提高效率吗?需要! BufferedWriter
BufferedWriter bufw = new BufferedWriter(fw);

扩展:想要把录入的数据按照指定的编码表(utf-8)将数据存到文件中。
目的:OutputStream Writer
   是不是纯文本?是!Writer
   设备:硬盘  一个文件 使用FileWriter。 FileWriter使用的是默认的编码表GBK

   但是存储时需要加入指定的编码表utf-8,而指定的编码表只有转换流可以指定。所以要使用的对象是OutputStreamWriter。
   该转换流对象要接收一个字节输出流,而且是可以操作文件的字节输出流 FileOutputStream。

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt","UTF-8"));

   需要提高效率吗?需要! BufferedWriter
BufferedWriter bufw = new BufferedWriter(osw);
记住:转换流什么时候用?字符和字节之间的桥梁。通常涉及到字符编码转换时,需要用到转换流。

import java.io.*;
class  TransStreamDemo2
{
public static void main(String[] args) throws IOException
{
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");
BufferedWriter bufw = new BufferedWriter(osw);

String line = null;
while ((line = bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}

bufr.close();
}
}

练习:将一个文本数据打印到控制台上。要按照以上格式自己完成三个明确。
   

五、改变标准输入输出设备
java.lang包中的System类

方法:
static void setIn(InputStream in) 重新分配“标准”输入流。 
static void setOut(PrintStream out) 重新分配“标准”输出流。 

Demo:
import java.io.*;
class  TransStreamDemo2
{
public static void main(String[] args) throws IOException
{
System.setIn(new FileInputStream("PersonDemo.java"));//设置输入
System.setOut(new PrintStream("zz.txt"));//设置输出

BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

String line = null;
while ((line = bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}

bufr.close();
}
}

六、异常的日志信息
java.lang包中的Throwable类
   |----   void printStackTrace() 将此 throwable 及其追踪输出至标准错误流。 
   |----   void printStackTrace(PrintStream s) 将此 throwable 及其追踪输出到指定的输出流。

Demo:
import java.io.*;
class  TransStreamDemo2
{
public static void main(String[] args) throws IOException
{
System.setIn(new FileInputStream("PersonDemo.java"));//设置输入
System.setOut(new PrintStream("zz.txt"));//设置输出

BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

String line = null;
while ((line = bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}

bufr.close();
}
}
/*
打印结果为:
2014-09-26 22:44:34
java.lang.ArrayIndexOutOfBoundsException: 3
at ExceptionInfo.main(ExceptionInfo.java:11)
*/

注:网络上有个专门搞java日志信息的工具包:log4j 
七、系统信息
java.lang包中的System类
   |----  static Properties getProperties() 确定当前的系统属性。

java.lang.Object
   |---- java.util.Dictionary<K,V>
|---- java.util.Hashtable<Object,Object>
   |----  java.util.Properties 
Properties类中 
void list(PrintStream out) 将属性列表输出到指定的输出流。 

import java.io.*;
import java.util.*;
class  SystemInfo
{
public static void main(String[] args) throws IOException
{
Properties prop = System.getProperties();

//System.out.println(prop);//将系统信息打印在控制台上,切没有换行
prop.list(new PrintStream("sysinfo.txt"));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息