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

黑马程序员 java基础<四>--IO流(2)

2013-04-24 11:15 831 查看
-------android培训java培训java学习型技术博客、期待与您交流!
----------

知识点二 字节流

一、概述:

1、字节流的操作原理和字符流类是相似的,只不过字节流可以对图片、音频和视频媒体进行操作。

2、由于媒体数据中都是以字节存储的,所以,字节流对象可直接对媒体进行操作,可以不用再进行刷新流的动作。

3、读写字节流:InputStream ---> 输入流(读)

OutputStream ---> 输出流(写)

4、不用进行刷新流的动作的原因:

因为字节流操作的是字节,即数据的最小单位,不需要像字符流一样要进行转换为字节。可直接将字节写入到指定文件中,但是需要在写代码的时候,如果有字符串,要将字符串转为字节数组再进行操作。

5、字节流所特有方法:

int available() ---> 放回数据字节的长度,包含终止符

在定义字节数组长度的时候,可以用到这个方法:byte[] = new byte[fos.available()] (fos为字节流对象)

但是,对于这个方法要慎用,如果字节过大,比如一部电影(几个G),那么如此大的数组就会损坏内存,超过jvm所承受的大小(指定内存为64M)。

举例:

/*
字符流:
FileReader
FileWriter

BufferedReader
BufferedWriter

字节流:
两个基类:
InputStream(读) OutputStream(写)

需求:想要操作图片数据,这时候就要用到字节流
*/
import java.io.*;
class FileStream{
public static void main(String []args) throws IOException
{
// writeFile();
// readFile_1();
// readFile_2();
readFile_3();
}
public static void readFile_1() throws IOException
{
FileInputStream fis=new FileInputStream("fos.txt");

int ch=0;
while((ch=fis.read())!=-1)
{
System.out.println((char)ch);
}
fis.close();
}

public static void readFile_2() throws IOException
{
FileInputStream fis=new FileInputStream("fos.txt");

//以这种方式为主,这是最好,最优化的方式
byte[] buf=new byte[1024];
int len=0;
while((len=fis.read(buf))!=-1)
{
System.out.println(new String(buf,0,len));
}

fis.close();
}

public static void readFile_3() throws IOException
{
FileInputStream fis=new FileInputStream("fos.txt");

// int num=fis.available();

//这种方式要慎用,数据不是太大的话,可以这样使用
byte[] buf=new byte[fis.available()];//定义一个刚刚好的缓冲区,不用再循环了

fis.read(buf);

// System.out.println("num="+num);
System.out.println(new String(buf));

fis.close();
}

public static void writeFile() throws IOException
{
FileOutputStream fos=new FileOutputStream("fos.txt");

//将字符串变为字节数组
fos.write("abcde".getBytes());

fos.close();

}
}


二、复制媒体文件(一张图片):

1、思路:

1)用字节流读取流对象和媒体文件相关联

2)用字节写入流对象,创建一个媒体文件,用于存储获取到的媒体文件数据

3)通过循环读写,完成数据的存储

4)关闭资源

注意:不要用字符流操作媒体文件,因为图片数据读取一段后去查编码表,如果找到对应的数字编码未变话,如果没找到去找编码表的未知区域,所以编码会发生变化,这样生成新图片的编码和老图片的编码就不一样了,字节码发生变化,因此字符流只用于处理文字数据。

示例:

import java.io.*;
class  CopyPic
{
public static void main(String[] args)
{
FileOutputStream fos = null;
FileInputStream fis = null;
try
{
fos = new FileOutputStream("c:\\2.bmp");
fis = new FileInputStream("c:\\1.bmp");

byte[] buf = new byte[1024];

int len = 0;

while((len=fis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
}
catch (IOException e)
{
throw new RuntimeException("复制文件失败");
}
finally
{
try
{
if(fis!=null)
fis.close();
}
catch (IOException e)
{
throw new RuntimeException("读取关闭失败");
}
try
{
if(fos!=null)
fos.close();
}
catch (IOException e)
{
throw new RuntimeException("写入关闭失败");
}
}
}
}
三、字节流缓冲区:

1、读写特点:

read():会将字节byte型值提升为int型值

write():会将int型强转为byte型,即保留二进制数的最后八位。

2、原理:将数据拷贝一部分,读取一部分,循环,直到数据全部读取完毕。

1)先从数据中抓取固定数组长度的字节,存入定义的数组中,再通过然后再通过read()方法读取数组中的元素,存入缓冲区

2)循环这个动作,知道最后取出一组数据存入数组,可能数组并未填满,同样也取出包含的元素

3)每次取出的时候,都有一个指针在移动,取到数组结尾就自动回到数组头部,这样指针在自增

4)取出的时候,数组中的元素再减少,取出一个,就减少一个,直到减到0即数组取完

5)到了文件的结尾处,存入最后一组数据,当取完数组中的元素,就会减少到0,这是全部数据就取完了

示例:

/*
通过缓冲区,演示Mp3的复制

BufferedOutputStream
BufferedInputStream
*/
import java.io.*;
class CopyMp3{
public static void main(String []args) throws IOException
{
long start=System.currentTimeMillis();
//copy_1();
copy_2();
long end=System.currentTimeMillis();

System.out.println((end-start)+"毫秒");
}

//通过字节流的缓冲区,完成复制
public static void copy_1() throws IOException
{
//缓冲区里已经定义了数组
BufferedInputStream  bufis=new BufferedInputStream(new FileInputStream("C:\\0.mp3"));
BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("C:\\1.mp3"));

int by=0;

while((by=bufis.read())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.close();
}

public static void copy_2() throws IOException
{
MyBufferedInputStream bufis=new  MyBufferedInputStream(new FileInputStream("C:\\0.mp3"));
BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("C:\\2.mp3"));

int by=0;

//读了一次没有写出去
// System.out.println("第一个字节:"+bufis.myRead());

while((by=bufis.myRead())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.myClose();
}
}


4、自定义字节流缓冲区:

思路:

1、定义一个固定长度的数组

2、定义一个指针和计数器用于读取数组长度,和计数数组元素是否取完为0

3、每次将字节数据存入元素要先将数组中的元素取完

注:取出的是byte型,返回的是int型,这里存在提升的动作,

当byte中的八位全为1的时候是byte的-1,提升为int类型,就变为int型的-1,,read循环条件就结束了

变为-1的原因是由于在提升时,将byte的八位前都补的是1,即32位的数都是1,即为int型的-1了。

如何保证提升后的最后八位仍为1呢?就需要将前24位补0,就可以保留原字节数据不变,又可以避免转为int型出现-1的情况;

那么要如何做呢?
这就需要将提升为int的数据和前24位为0,后八位仍为原字节数据的这个值做与运算。即和255做与运算即可

示例:

/*
11111111 -->提升了一个int类型,那不还是-1,吗?是-1的原因是因为在8个1的前面补得的是1导致的
那么我只要在前面补0,既可以保留原字节数据不变,又可以避免-1的出现,那么怎,补0呢

11111111 11111111 11111111 11111111
&00000000 00000000 00000000 11111111
-------------------------------------
00000000 00000000 00000000 11111111

这样就可以避免-1的发生
byte:-1  ---->int:-1
read方法在提升,write方法将指定的字节写入此缓冲的输出流(强制转换,取最低的8位)
*/

import java.io.*;
class MyBufferedInputStream{
private InputStream in;

private byte[] buf=new byte[1024*4];

private int pos=0;

private int count=0;
MyBufferedInputStream(InputStream in)
{
this.in=in;
}

//一次读一个字节,从缓冲区(字节数组)获取
public int myRead() throws IOException
{
//通过in对象,读取硬盘上的数据,并存储到buf中
if(count==0)
{

count= in.read(buf);
if(count<0)
return -1;
pos = 0;
//取数组第一个元素pos=0;
byte b=buf[pos];

count--;
pos++;
//b与255进行与操作,用十六进制表示就是0xff
return b&255;
}else if(count>0)
{
byte b=buf[pos];

count--;
pos++;
//b与255进行与操作,用十六进制表示就是0xff
return b&255;
}

return -1;
}
public void myClose()throws IOException
{
in.close();
}

}
5.读取键盘录入

System.out:对应的是标准的输出设备,控制台。

System.in:对应的标准输入设备,键盘

/*
需求:
通过键盘录入数据,当录入一行数据后就进行打印。
如果当录入的数据时over,那么停止录入

Dos下键盘录入操作终止可以使用Ctrl+C操作
*/

import java.io.*;

class  ReadIn
{
public static void main(String[] args) throws IOException
{
InputStream in=System.in;
StringBuilder sb=new StringBuilder();
/*
int ch=0;
while((ch=in.read())!=-1)
{
System.out.println(ch);
}
*/
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=new StringBuilder();

sb.delete(0,sb.length());
}
else
sb.append((char)ch);
}

in.close();
//数据类型转换
System.out.println('\r'+0);
System.out.println('\n'+0);
/*
int by=in.read();
int by1=in.read();
int by2=in.read();

System.out.println(by);
System.out.println(by1);
System.out.println(by2);
*/
}
}

知识点三 转换流

一、概述:

转换流的由来:内部可以指定编码表

1.通过上面的示例,通过键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理

能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?

readLine方法是字符流BufferedReader类中的方法

而键盘录入的read方法字节流InputStream的方法

那么能不能将字节流转成字符流在使用字符流缓冲区的readLine方法呢?



2.两个转换流:[b]读取转换流[b]InputStreamReader[/b]和写入转换流OutputStreamWriter,这两个类分别属于字符流Reade和Writer的子类[/b]

二、读取转换流:

InputStreamReader是字节流通向字符流的桥梁,它使用指定的charset读取字节并将其解码为字符。

InputStreamReader:读取转换流

a.获取键盘录入对象: ---> InputStream in = System.in;

b.将字节流对象转换成字符流对象,使用转换流InputStreamReader: ---> InputStreamReader isr = new InputStreamReader(in);

c.为提高效率,将字符串进行缓冲区技术操作,使用BufferedReader: ---> BufferedReader bufw = new BufferedReader(isr);

d.之后就可以使用readLine()方法读取录入的一行数据了。

示例:

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

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

//为了提高效率,讲将字符流进行缓冲区技术的高效操作

// BufferedReader bufr=new BufferedReader(isr);

BufferedReader bufr=new BufferedReader(new InputStreamReader(new FileInputStream("CopyMp3.java")));

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());

}
bufr.close();
}
}


二、写入转换流

OutputStreamWriter是字符流通向字节流的桥梁,可使用指定的charset将要写入流中的字符编码成字节。

OutputStreamWriter:写入转换流 ---> 和读取转换流同理,即使用对应的Writer的子类



示例:

class TransStreamDemo{
public static void main(String []args) throws IOException
{

//*************毕老师说这句换一定要记住,键盘录入,非常的重要********************
//键盘录入最常见写法
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();
}
}


知识点四 流操作规律

一、分析清楚源和目的以及需求:

1.源:键盘录入

目的:控制台

2.需求:想把键盘录入的数据存储到一个文件中源:键盘

目的:文件

3.需求:想要将一个文件的数据打印在控制台上。源:文件

目的:控制台

二:
流操作的基本规律:

最痛苦的就是流对象有很多,不知道该用哪一个

通过三个来明确

1.明确源和目的

源:输入流 InputStream Reader

目的:输出流 OutputStream Writer



2.明确操作的数据是否是纯文本

是:字符流

不是:字节流



3.当体系明确后,在明确要使用哪个具体的对象 通过设备来进行区分;

源设备:内存(ArrayStream),硬盘(FileStream),键盘(System.in)

目的设备:内存(ArrayStream),硬盘(FileStream),控制台(System.out)。

4、需求体现:


4.1需求:将一个文本文件中的数据存储到另一个文件中,复制文件。

源:因为是源,所以使用读取流 InputStream Reader

是不是操作文本文件?

是!这时就可以选择Reader

这样体系就明确了

接下来明确对象该体系中的哪个对象。

明确设备:硬盘上的一个文件。

Reader体系中可以操作文件的对象是FileReader

是否需要提高效率:是!加入Reader体系中的缓冲区,BufferedReader

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

BufferReader bufr=new BufferedReader(fr);

目的:OutputStream Writer

是否是纯文本文件?

是!Writer。

设备:硬盘。一个文件。

Writer体系中可以操作文件的对象是FileWriter

是否需要提高效率:是!加入Writer体系中的缓冲区,BufferedWriter

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

BufferedWriter bufw=new BufferedWriter(fw);

练习:将一个图片文件中数据存储到另一个文件中,复制文件。要按照以上格式完成三个明确。


分析:

1)源:InputStream和Reader

图片:字节流 ---> InputStream

设备:硬盘上的文件 ---> FileInputStream

2)目的:OutoutStream和Writer

图片:字节流 ---> OutputStream

设备:硬盘上的文件 ---> FileOutputStream

4.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);

目的:OutputputStream Writer

是否是纯文本?是!Writer

设备:硬盘。一个文件。使用FileWriter

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

需要提高效率吗?需要

BufferedWriter bufw=new BufferedWriter(fw);


5.扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中


目的:OutputputStream Writer

是否是纯文本?是!Writer

设备:硬盘。一个文件。使用FileWriter

但是FileWriter是使用默认的编码表,GBK

但是存储时需要加入指定的编码表utf-8,只有转换流才能指定。

所以要使用的对象是OutputStreamReader

而该转换流对象要接受一个字节输出流,而且还可以操作文件的字节输出流。FileOutputStream

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

需要提高效率吗?需要

BufferedWriter bufw=new BufferedWriter(osw);

所以记住,装换流什么时候使用,字符和字节之间的桥梁,通常,涉及到字符编码装换时需要用到转换流
示例:
class TransStreamDemo2{
public static void main(String []args) throws IOException
{
//获取键盘录入对象
// InputStream in=System.in;

//键盘录入最常见写法
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));

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

String line=null;

while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;

bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
}
}
6.改变标准输入输出设备

System.setIn(new FileInputStream("PersonDemo.java"));

System.setOut(new PrintStream("zz.txt"));

知识点五 信息

一、异常的日志信息:

当程序在执行的时候,出现的问题是不希望直接打印给用户看的,是需要作为文件存储起来,方便程序员查看,并及时调整的。
示例:
/*
说明:Log4j的jar包可以完成日志信息建立
*/
import java.io.*;
import java.util.*;
//格式化要用的包
import java.text.*;

class ExceptionInfo
{
public static void main(String[] args) throws IOException
{
try{

int[] arr=new int [2];
System.out.println(arr[3]);

}catch(Exception e)
{
try{
//打印日期
Date d=new Date();
//SimpleDateFormat将时间格式化
SimpleDateFormat sdf=new  SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//h是12小时制,H是24小时制
String s=sdf.format(d);

PrintStream ps=new PrintStream("exception.log");
//ps是字节流,要将字符串变成字节数组写出去
//ps.write(d.toString().getBytes);
//ps.println(d.toString());
ps.println(s);
//改变标准输出
System.setOut(ps);
//e.printStackTrace(new PrintStream("a.txt"));
}catch(IOException ex)
{
throw new RuntimeException("日志文件创建失败");
}

e.printStackTrace(System.out);
}

}

}


二、系统信息:
获取系统信息:

Properties getProperties()

将信息输出到指定输出流中

void list(PrintStream out)

将输出流中数据存入指定文件中

new PrintStream("systeminfo.txt")

示例:

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(System.out);
prop.list(new PrintStream("sysinfo.txt"));
}
}


最新最全的的java学习视频教程:http://pro.net.itcast.cn/View-22-1458.aspx

-------android培训java培训、java学习型技术博客、期待与您交流!
----------

详细请查看:http://edu.csdn.net/heima
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: