IO
IO中的流对象 | ||
InputStream OutputStream | 字节流 |
|
BufferedInputStream BufferedOutputStream | 字节缓冲区 |
|
ByteArrayInputStream ByteArrayOutputStream | 操作字节数组 |
|
DataInputStream DataOutputStream |
|
|
FileInputStream FileOutputStream | 操作图片、音视频等文件 |
|
FilterInputStream FilterOutputStream |
|
|
ObjectInputStream ObjectOutputStream | 操作对象 |
|
PipedInputStream PipedOutputStream |
|
|
|
|
|
Reader Writer | 字符流 |
|
BufferedReader BufferedWriter | 字符流缓冲区 |
|
CharArrayReader CharArrayWriter | 操作字符数组 |
|
StringReader StringWriter | 操作字符串 |
|
FileReader FileWriter | 操作文本文件的 |
|
InputStreamReader OutputStreamWriter | 转换流 |
|
PipedReader PipedWriter |
|
|
FilterReader FilterWriter |
|
|
|
|
|
LineNumberInputStream |
|
|
LineNumberReader |
|
|
|
|
|
PrintStream | 字节打印流 |
|
PrintWriter | 字符打印流 |
|
|
|
|
PushbackInputStream |
|
|
PushbackReader |
|
|
|
|
|
SequenceInputStream |
|
|
StringBufferInputStream | 操作字符串的字节流 |
|
|
|
|
Console |
|
|
File | 用于封装文件 |
|
FileDescriptor |
|
|
FilePermission |
|
|
ObjectInputStream.GetField |
|
|
ObjectOutputStream.PutField |
|
|
ObjectStreamClass |
|
|
ObjectStreamField |
|
|
RandomAccessFile |
|
|
SerializablePermission |
|
|
StreamTokenizer |
|
|
目的 源 | 内存 | 文件 | 控制台 | Sokcet |
内存 |
|
|
|
|
文件 |
|
|
|
|
Socket |
|
|
|
|
IO大纲
字符流
FileWriterFileReader:
1FileWriter
2文件的续写,
3文本文件的读取方式1,
4文本文件的读取方式2,
5拷贝文本文件
bufferedWriterbufferedReader:
2、通过缓冲区复制文本文件,
3、readLine()方法的原理,
4、MyBufferedReader
装饰设计模式:
1、装饰设计模式,2、装饰和继承的区别,3、自定义装饰类
LineNumberReader:
1、LineNumberReader,
2、MyLineNumberReader
字节流
FileInputStreamFileOutputStream:
1字节流File读写操作,
2拷贝图片
BufferedInputStreamBufferedOutputStream:
字节流缓冲区,
自定义字节流的缓冲区 read和write的特点,
读取键盘录入
转换流
流的常规操作
流的常规操作规律-1,流的常规操作规律-2
其他操作
改变标准输入输出设备,异常的日志信息,系统信息
流操作文件:File对象
创建,删除,判断,获取,文件列表-1,文件列表-2,列出目录下所有内容--递归,列出目录下所有内容--带层次,删除带内容的目录,创建java文件列表
Properties
存取,存取配置文件,练习
其他流对象
PrintWriter,
合并流,
切割流,
对象的序列化,
管道流,
RandomAccessFile,
操作基本数据类型的流对DataStream,
ByteArrayStream
转换流的字符编码
字符编码
联通
练习
第一章 字符流
第一节 FileWriter
1、FileWriter
FileWriter的继承结构是:lang.object>io.Writer> io.OutputStreamWriter
构造方法摘要 | |
FileWriter(File file) |
|
FileWriter(File file, boolean append) |
|
FileWriter(FileDescriptor fd) |
|
FileWriter(String fileName) |
|
FileWriter(String fileName, boolean append) |
|
从类 java.io.OutputStreamWriter 继承的方法 |
从类 java.io.Writer 继承的方法 |
使用FileWriter对象,写入数据的步骤:1 导包,2 创建一个FileWriter对象。需要注意的是:该对象一被初始化就必须要有要操作的对象,如果该目录下已有指定的要操作的同名文件,原有文件将被覆盖。3 使用write方法向目标文件中写入数据fw.write("abc");4 刷新fw.flush() ;5 fw.write("def") ;会写在abc后面;6 fw.flush();关闭流资源,关闭前会刷新fw.close();
2文件的续写,
API中FileWriter有构造函数FileWriter(String fileName,boolean append) 。可用于在文件的原有数据上加入数据,而不去覆盖原文件。如果参数append为 true,则将数据写入文件末尾处,而不是写入文件开始处。
3文本文件的读取方式1,读取单个字符就操作
Reader不用刷新,使用Reader的read方法读取的是字符。可以一次读取单个字符然后操作,或是将读取到的字符缓存入字符数组然后操作,不能直接读字符串。Reader使用的是默认的字符编码,使用System.getPorperties()可以得到系统信息。read()返回类型是int 可以根据需要将其强转成(char)。
特点:此方法会自动往下读,读到流的末尾返回-1,并且一直阻塞
使用read()方法读取一次读取单个字符。示例代码
FileReaderfr = new FileReader(c:\\demo.txt);
intch = 0 ;
while((ch =fr.read())!=-1){
//对读取的字符进行操作
}
4文本文件的读取方式2,
读取单个字符,将其存入指定大小的字符数组,待将数组装满,再对结果操作
read(char[]cbuf) 返回的是读到的字符个数,数据类型是int 。使用此方法可以将数据缓冲入cbuf中。
通常为了方便,要将得到的cbuf转换为String类型。方法是new String(cbuf,0,num) ,其中num是read的返回值,这样就将字节数组cbuf中的0~num个字节转成了一个字符串,num是读到的字符个数,即cbuf中的有效字符个数,避免了无效字符的产生。
特点:读到末尾返回-1一直阻塞
示例代码
FileReaderfr = new FileReader(c:\\demo.txt);
//定义一个指定大小的字符数组,用以缓存read读到的字符
byte[]cbuf = new byte[1024] ;
int num = 0 ;
while((num =fr.read(cbuf))!=-1){
//对读取的字符进行操作
}
5拷贝文本文件
第二节 bufferedWriter bufferedReader
1、BufferedWriter BufferedReader
字符流缓冲区1、缓冲区的出现提高了对数据的读写效率,在创建缓冲区钱,要操作的流对象必须存在。2、对应类:BufferedWriter和BufferedReader3、缓冲区使用时要结合流4、在流的基础上对流的功能进行了增强5、出现了新的方法。
BufferedWriterBufferedReader是Writer和Reader的子类。继承了它们的读写方法,同时有自己更加功能更实用的方法。
BufferedWriter的void write(int c) ,写入单个字符,write(char[] cbuf, int off,int len) 写入字符数组的某一部分,write(Strings, int off, int len) 写入字符串的某一部分,newLine()写入一个行分隔符,这个方法在各种平台通用。有自己的刷新的关闭方法。
BufferedReader的readLine()方法可以一次读取一行,但不包含终止符,如果读到流的末尾返回null。他的结束标记是回车符,返回类型是String。
2、通过缓冲区复制文本文件,
readLine方法读取的数据不包含行终止符,所以读取一行后,要加入换行符;
并且写入后一定要刷新,如果不刷新,数据将保留在缓冲区中,刷新后数据才被写进目标;
缓冲区提高了FileWriter的效率,但真正和文件相关联并对文件进行操作的是FileWriter缓冲区的关闭,实际上关闭的是调用底层资源的流对象。
3、readLine()方法的原理,
无论是读一行,获者读取多个字符。都必须在硬盘上一个一个字符读取,所以最终使用的还是一次读取一个的read方法,。readLine方法内部封装了一个数组,使用read方法读取一个字符后,并没有将这个字符返回给下一步的操作者,而是将其存储在数组中,直到读到换行符的\r时,再调用一次read方法读取一个字符,如果这个字符是\n,就将数组中的数据一次性返回给下一步的操作者。
4、MyBufferedReader
MyBufferedReader{
private Reader r ;
MyBufferedReader(Readerr){
this.r= r ;
}
public String myReadLine(){
StringBuilder sb = new StringBuilder();
int ch;
while((ch = read() )!=-1) {//使用传入的功能
if(ch == ’\r’)
coutinue;
if(ch == ‘\n’){
returnsb.toString();
}
else
sb.append((char)ch); //添加前要转换为char,
}
return null ;
}
}
第三节 装饰设计模式
1、装饰设计模式,
当想要对已有的对象的功能进行增强时,可以定义一个类,将想要增强的类传入,并基于已有的功能,提供新的更强大的功能。这种方法我们称之为装饰设计模式。增强类称之为装饰类。
装饰类基于被装饰类,并且通常装饰类和被装饰类属于同一个体系。
2、装饰和继承的区别
装饰设计模式的由来
是专门用于读取文本数据的类,它有一些子类。在使用MyReader子类读文本时,发现效率低,想到了缓冲技术,由MyReader的子类衍生出了一些用于缓冲的子类。
下面是它的继承体系。
MyReader
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
|--MyDataReader
|--MyBufferDataReader
如果MyReader的每个直接子类都需要增强,这样产生的继承体系,臃肿复杂,这个时候就需要对现有的体系进行优化。思路是可以定义一个类,将需要缓冲的MyReader的直接子类作为参数传入。
MyReader直接子类原来的功能是读,定义的装饰类增强了读取的功能,所以装饰类的功能也是读取,因此也应该是MyReader体系中的一员,所以它应该继承MyReader。
classMyBufferedReaer() extends MyReader
{
privateReader r ;
MyBufferedReaer(MyReaderr)
{
this.r= r ;
}
//增强功能
}
这样,原来的体系就变得简单起来,MyReader直接子类和装饰类的关系由继承变成了组合
MyReader
|--MyTextReader
|--MyMediaReader
|--MyDataReader
|--MyBufferBufferReader
装饰类对原有对象的功能进行了增强,它具备的功能和原有对象的功能都可以达到同样的目的。但是装饰类的功能使用起来更加方便。
所以装饰类和被装饰类通常都是属于同一个体系.
3、自定义装饰类
在定义装饰类时,定义的增强功能因为原有功能而有可能产生异常时,不能捕捉,而应该抛出,让调用者处理。
第四节 LineNumberReader:
1、LineNumberReader
LineNumberReader是BufferedReader子类,是可以跟踪行号的缓冲字符输入流。
此类定义了方法setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。并且有readLine()方法。
2、MyLineNumberReader
import java.io.*;
class MyLineNumberReader extends BufferedReader
{
private int lineNumber ;
MyLineNumberReader(Readerr)
{
super(r) ;
}
public StringmyReadLine() throws IOException
{
//每调用一次myReadLine() lineNumber自增1 ;
lineNumber++ ;
returnsuper.readLine();
}
//特有方法
public void setLineNumber(int lineNumber)
{
this.lineNumber =lineNumber ;
}
public int getLineNumber()
{
returnlineNumber;
}
}
第二章 字节流
第一节 FileInputStreamFileOutputStream:
字节流的read方法读取的是字节,可以读取单个字符,或是将读取的字符存入字节数组。available()方法返回字符的个数( \r 和\n分别是一个字节)。可以使用这个方法定义一个大小等于源的缓冲区。
1字节流File读写操作
字节流write方法不用刷新。
一次读一个字节
FileInputStreamfis = new FileInputStream(“c:\\demo.txt”);
FileOutputStreamfos = new FileOutputStream(c:\\demo_1.txt) ;
int len = 0 ;
while((len= fis.read())!=-1){
fos.write(len);
}
读入字节数组中,然后写入目标
FileInputStreamfis = new FileInputStream(“c:\\demo.txt”);
FileOutputStreamfos = new FileOutputStream(c:\\demo_1.txt) ;
byte[] b = newbyte[1024];
int num = 0 ;
while((num= fis.read(b))!=-1){
fos.write(b,0,num);
}
available()方法的使用
FileInputStreamfis = new FileInputStream(“c:\\demo.txt”);
FileOutputStreamfos = new FileOutputStream(c:\\demo_1.txt) ;
byte[] b = newbyte[fis.available()];
fis.read(b);
fos.write(b);
2拷贝图片
第二节BufferedInputStream BufferedOutputStream:
1字节流缓冲区
2自定义字节流的缓冲区 read和write的特点
读取字节时,如果读到连续八个1,连续的八个1对应的是整数-1,程序会错误地以为是结束标记,会停止读取,导致目标文件不完整,复制失败。
为什么返回的是int而不是byte
11111111 ——>提升为一个int类型,那不还是-1吗?是-1的原因是,在八个1前面补了1,那么在八个1前面补0,就可以避免这种-1,即可以保留原字节数据不变,由可以避免-1的出现
所以用int接收byte,将其类型提升。然后使用&255的方式,在原数据前补0 ,避免了读到连续八个一,等于-1,和结束标记相等 的情况。如下图
byte:-1 ——> int:-1 ;
00000000 00000000 00000000 11111111 255,
11111111 11111111 11111111 11111111 -1
取最后4位:&15() 取最后8位&255
import java.io.*;
class MyBufferedInputStream
{
private InputStream in ;
private byte[] buf = newbyte[1024*1024];
private int pos = 0 ,count = 0;
MyBufferedInputStream(InputStreamin)
{
this.in = in ;
}
//一次读一个字节,从缓冲区(字节数组)获取
public int myRead() throws Exception
{
//通过in对象读取硬盘上数据,并存储buf中
if(count == 0 )
{
count = in.read(buf);
if(count<0)
return -1;
pos = 0 ;
byte b = buf[pos];
count -- ;
pos++ ;
return b&255/*255的十六进制表现形式*/ ;
}
else if(count>0)
{
byte b = buf[pos];
count -- ;
pos++ ;
return b&255;
}
return -1 ;
}
public voidmyClose()throws Exception
{
in.close();
}
public static voidcopyMp3()throws Exception
{
MyBufferedInputStreambis =
newMyBufferedInputStream(new FileInputStream("c:\\王麟 - 当爱情离开的时候.mp3"));
BufferedOutputStreambos =
newBufferedOutputStream(new FileOutputStream("c:\\王麟 - 当爱情离开的时候_copy.mp3"));
//byte[] buf =new byte[1024*1024];
//int len = 0 ;
int by = 0 ;
while((by =bis.myRead())!=-1)
{
bos.write(by);
}
bis.myClose();
bos.close();
}
public static voidmain(String[] args) throws Exception
{
long start =System.currentTimeMillis();
System.out.println(start);
copyMp3();
long end =System.currentTimeMillis();
System.out.println(end);
System.out.println("用时"+(end-start)+"毫秒");
}
}
3读取键盘录取
使用字节流进行键盘录入
InputStream in = System.in;
StringBuildersb = new StringBuilder();
while(true)
{
Strings = null ;
intch = in.read();
if(ch== '\r')
continue;
if(ch== '\n')
{
s= sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
sb.delete(0,sb.length());
}
else
{
sb.append((char)ch);
}
}
第三章 转换流
InputStreamReader OutputStreamWriter
第四章 流的常规操作
OutputStreamWriter可以指定编码表
怎么选择流对象?
1明确源和目的
源:输入流 InputStream Reader
目的:输出流 OutputStream Writer
2操作的数据是否是存文本
是:用字符流
否:字节流
3当体系明确后,再明确使用哪个具体的对象
源:内存,硬盘,键盘
目的:内存,硬盘,控制台
第五章 其他操作
第一节 改变标准输入输出设备
static void | setIn(InputStream in) |
static void | setOut(PrintStream out) |
第二节 异常的日志信息
异常的日志信息,以下是异常日志信息的建立方式。但真正开发时,不用这样的方法,在网络上有一个专门建立java日志信息的工具包log4j。
import java.io.*;
import java.util.*;
import java.text.*;
class ExceptionInfo
{
public static voidmain(String[] args)
{
try
{
int[] arr= new int [2] ;
System.out.println(arr[3]);
}
catch (Exceptione)
{
try
{
Dated = new Date();
SimpleDateFormatsdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Strings = sdf.format(d);
PrintStreamps = new PrintStream("c:\\ExceptionInfo.txt");
ps.println(s);
System.setOut(ps);
}
catch(IOException e2)
{
thrownew RuntimeException("创建异常日志文件失败");
}
e.printStackTrace(System.out);
}
}
}
第三节 系统信息
System类中的static Properties getProperties() 方法可以得到系统信息。Properties类可以
和流相结合
import java.util.*;
import java.io.*;
class GetProperties
{
publicstatic void main(String[] args) throws IOException
{
Propertiesprop = System.getProperties();
System.setOut(newPrintStream("systeminfo.txt"));
prop.list(System.out);
}
}
第五章 流操作文件:File对象
创建,
删除,
判断,
获取,
文件列表-1,
文件列表-2,
列出目录下所有内容--递归,
列出目录下所有内容--带层次,
importjava.io.*;
递归的英文是单词recursion
在列出目录的过程中,因为目录中还有目录,只要使用同一个列出目录功能的函数即可完成。在列出过中出现的还是目录的话,还可以再次调用本功能,也就是函数自身调用自身。这种表现形式,或者编程手法称为递归。
递归要限定循环条件,如if等。要不然会死循环;而且要注意递归次数,避免内存溢出。
下面是使用递归的思想列出一个目录下的所有文件和目录
class RecursionDemo
{
public static void main(String[] args)
{
File f = newFile("F:\\1115java\\javawork");
showDir(f);
//showDirlist(f);
}
public static void showDir(File f)
{
int x = 0;
so.p(" "+f);
File[] files = f.listFiles();
for(File f2 : files ){
x++ ;
//如果是目录,调用showDir方法.
if(f2.isDirectory())
{
showDir(f2);
}
//如果不是目录,打印。
else
so.p("file"+x+":"+f2);
}
}
//插入层级目录
public static String getLevel(int level)
{
StringBuilder sb = newStringBuilder();
sb.append("|————");
for(int x = 0; x<level ;x++ )
{
sb.intsert(0," ");
}
}
public static void showDirlist(File f)
{
int x = 0;
String[] strs = f.list();
for(String str : strs ){
x++ ;
so.p("strs"+x+" :"+str);
}
}
}
删除带内容的目录,
创建java文件列表
第六章 Properties
Properties的继承结构
java.lang.Object>
java.util.Dictionary<K,V> >
java.util.Hashtable<Object,Object>
>java.util.Properties
存取
存取配置文件
练习
第七章 其他流对象
PrintWriter,
合并流
SequenceInputStream有构造函数SequenceInputStream(Enumeration<?extends InputStream> e)
Vector集合可以得到Enumeration
1、所以我们可以将文件封装成读取流
FileInputStream(File file)FileInputStream(String name);//InputStream是抽象的
2、再将读取流封装成Vector集合
Vector<FileInputStream> v = newVector<FileInputStream>()
v.add(new FileInputStream(String name))
3、再由Vector集合的elements()方法 得到Enumeration
Enumeration<FileInputStream> e =v.elements();
切割流
为了达到切割文件的目的,可一讲一个输出流切成几个部分
思路
1将要操作的对象封装成流对象
2建立一个字节数组,这个字节数组的大小将成为切割后单个文件的大小标准。
3建立循环,循环一次,建立一个流,写入规定大小的数据,然后关闭流
import java.io.*;
class slitFile
{
public static voidmain(String[] args) throws Exception
{
splitFile();
System.out.println("HelloWorld!");
}
public static voidsplitFile()throws Exception
{
//1将操作对象封装成流对像
FileInputStreamfis = new FileInputStream("c:\\1.jpg");
//2
byte[] b = newbyte[1024*10];
//3
int count = 1;
int len = 0;
while((len= fis.read(b))!=-1)
{
FileOutputStream fos =
newFileOutputStream("c:\\"+(count++)+".part");
fos.write(b,0,len);
fos.close();
}
}
}
对象的序列化
管道流
RandomAccessFile,
操作基本数据类型的流对DataStream,
ByteArrayStream
第八章 编码
转换流的字符编码
字符编码
联通
练习