1. IO概念
IO流用来处理设备之间的数据传输;Java对数据的操作是通过流的方式Java用于操作流的类都在IO包中1)按照流向分为: 输入流和输出流;2)按照操作类型分为:字节流和字符流字节流抽象父类:InputStream、OutputStream字符流抽象父类:Reader、Writer字节流可以操作任何数据,字符流只能操作纯字符数据。(拷贝的时候使用字节流效率高)
2.字节流
1)常用方法:InputStream
read(); //读取一个字节read(byte[]); //读取多个字节;available(); //获取可读的字节数skip(int) //跳过若干个字节close(); //关闭流,释放资源
OutputStream
write(int); //写出一个字节write(byte[]); //写出数据中所有字节close(); //关闭流,释放资源
2)BufferedInputStreamBufferedInputStream内置了一个缓冲区,从BufferedInputStream中读取一个字节时,它会一次性从文件中读取8192个存在缓冲区中,返回给程序一个,程序再次读取时直接从缓冲区获取直到缓冲区中所有的都被读完再重新从文件中读取。3)BufferedOutputStreamBufferedOutputStream中也内置了一个缓冲区,程序向流中写出字节时不会直接写到文件,而是先写到缓冲区中,直到缓冲区写满,BufferedOutputStream才会把缓冲区中的数据一次性写到文件里。
3.关于read()方法返回值为int类型的解释:
返回值为0-255范围内的int字节值。之所以返回int不是byte的原因:当使用字节流读取数据时,字节流什么数据都可以读如:MP3、电影、图片等,这些文件都是由字节组成的,很有可能会有-1,如果返回的byte值为-1程序就会终止,这样会有文件损失没有读全,返回值为int其实是在byte的八位的二进制的基础上加上了24个0,返回值本来是在-128-127之间结果就变成了0-255之间的,因此返回值设置为int就是为了结束标记用的。
4. JDK 1.7新特性
try(//小括号中定义的流是不用调用close方法可以直接关闭,前提是这些流实现了 AutoCloseable 接口){}
5. 装饰设计模式举例
interface Coder {void printCode();}class Student implements Coder {public void printCode(){System.out.println("java");}}class SuperStudent implements Coder {Student student;SuperStudent(Student student){this.student = student;}public void printCode(){System.out.println("Java");System.out.println("C++");System.out.println("PHP");}}
6.Properties类
常用方法:setProperty(String key,String value);getproperty(String key);load(new FileInputStream("config.properties"));prop.load(new FileInputStream("config.properties"));prop.setProperty("userName","张三"); //此时配置加载到内存中还不能修改属性文件prop.list(new PrintStream("config.properties")); //需要这一步将修改的结果输出到文件。
Properties props = System.getProperties();//获得当前系统属性
8.字符流
可以直接读写字符的IO流
1) 什么情况下使用字符流?
字符流也可以拷贝文本文件但并不推荐使用,因为读取时会把字节转为字符,写出时还要把字符转回字节;因此,程序需要读取一段文本或者需要写出一段文本的时候可以使用字符流。
2)FileReader、FileWriter
FileReader类的read()方法,可以按照字符的大小读取;FileWriter类的write()可以自动把字符转为字节写出。
3)带缓冲的字符流
BufferedReader的read()方法读取字符时会一次读取若干字符到缓冲区,然后逐个返回给程序,降低读取文件的次数,提高效率BufferedWriter的write()方法写出字符时会先写到缓冲区,缓冲区写满时才会写到文件,降低些文件的次数
4).LineNumberReader
LineNumberReader是BufferedReader的子类, 具有相同的功能, 并且可以统计行号
调用getLineNumber()方法可以获取当前行号
调用setLineNumber()方法可以设置当前行号
5)指定的码表读取字符
FileReader是使用默认码表读取文件, 如果需要使用指定码表读取, 那么可以使用InputStreamReader
FileWriter是使用默认码表写出文件, 如果需要使用指定码表写出, 那么可以使用OutputStreamWriter
Reader常用方法
int read(); //读取单个字符read:FileInputStream 字节流一次读一个字节FileReader 字符流一次读一个字符,有可能督导3个字节
Writer
flush(); //把流中的数据刷新到目的地,字符流不刷新写不进去;
close(); //在关闭之前先将流中的数据刷新到目的地再关闭;
bw.newLine() 与 "\r\n" 区别
字符流读是先将字节转换成字符,因为一次读的是一个字符,而文件上存的都是字节;写的时候是先将字符转成字节,因为一次写出的是一个字符,而文件上存的都是字节,字符流会自动将字符转换成字节。字符流不能读取音频视频文件,只能读文本
bw.newLine(); //跨平台"\r\n" 不跨平台; //linux "\n" ; Mac "\r" ; Windows "\r\n";bw.write(line);bw.flush(); //不用每次都刷新,因为缓冲区只要是满了就会自动刷新,只有最后一次没满需要刷新,在流中的数据就会被刷新出来,所以不用flush也可以,因为close()方法在关闭的时候会先刷新流中的数据再关闭。
转换流 InputStreamReader、OutputStreamWriter
只要同一端编码一致,就不会出现乱码问题
UTF-8 : 一个汉字用三个字节
使用转换流的好处:
用字节流直接复制一个文本的时候,如果两边文本的编码表一致,没问题;
但是如果从一个编码为UTF-8的文本上读,写到一个编码表为GBK的文本上
就会出现乱码,这时候可以使用转换流来解决问题。
File类:
构造函数File(String pathname);File(File parent,String child);File(String parent,Stringchild);常用方法:boolean exists();//判断文件是否存在boolean isDirectory();//是否是文件夹boolean isFile(); //是否是文件boolean isHidden();//是否是隐藏String getAbsolutePath();//获取绝对路径long getFreeSpace(); //获取当前盘符剩余空间long getTotalSpace(); //获取当前盘符的总空间long getUsableSpace(); //获取当前盘符可用空间String getParent(); // 获取父级路径,不指定父目录返回值为null;String getName(); //获取文件名
setReadable(false); //设置是否可读 -----这个属性在windows下不管用;setWritable(false); //设置是否可写setExecutable(false); //设置是否可执行----windows不管用canRead(); canWrite(); canExecute();
long(millis) lastModified(); //获取文件的最后修改时间setLastModified(long); //设置最后修改时间
lastModified()方法应用long time = f.lastModified();Date d = new Date(time);SimpleDateFormate sdf = new SimpleDateFormate("YYYY-MM-dd HH:mm:ss");
sdf.formate(d);
createNewFile(); //创建文件
mkdir(); //创建文件夹,仅一级;
mkdirs(); //创建多级文件夹(包含创建一级目录);
renameTo(File dest); //剪切+粘贴+重命名;
delete(); //删除文件,删文件夹时只能删除空的,不能走回收站
length(); //可以看文件大小,不能看文件夹大小;
list(); //湖区到路径下的文件夹和文件的名字;
listFiles(); //获取文件对象;
序列流---SequenceInputStream
1)什么是序列流?
可以把多个字节输入流整合成一个,从序列流中读取数据时,将从被整合的第一个流开始读,
读完第一个之后继续读第二个,依次类推;
2)使用方式
两个:SequenceInputstream(InputStream,InputStream);
整合多个:SequenceInputStream(Enumeration<InputStream>);
内存输出流
该输出流可以向内存中写数据,把内存当作缓冲区,写出之后可以一次性获取出所有数据。
ByteArrayOutputStream
使用方式:
创建对象 new ByteArrayOutputStream();
写出数据 write(int); write(byte[]);
获取数据: toByteArray();
对象操作流
ObjectInputStream、ObjectOutputStream
1.对象操作流:该流可以将一个对象写出或者读取一个对象到程序中,也就是执行了序列化和反序列化的操作。
2.使用方式:
打印流写出:new ObjectOutputStream(OutputStream out);writeObject();读取:new ObjectInputStream(InputStream in);readObject();要写出的对象必须实现Serializable 接口才能被序列化。
可以很方便的将对象的toString()结果输出,并自动加上换行,而且可以使用自动刷出的模式。
System.out 就是一个标准输出流,默认可以向Console中输出字符和字节数据。
使用方式:
打印:
自动刷出:PrintStream(OutputStream out,boolean autoflush,String encoding);print();println();
标准输入输出流:
1.System.in 是InputStream 标准输入流,默认可以从键盘输入读取字节数据。
2.System.out 是PrintStream 标准输出流,默认可以向Console中输出字符和字节数据。
修改:
System.setIn(InputStream);
System.setOut(PrintStream);
数据输入输出流:
DataInputStream、DataOutputStream 可以按照基本数据类型读取数据。
例如:按Long大小写出一个数字,写出时读数据占8个字节;读取也按照Long类型读取,一次读取8个字节;
使用:
DataInputStream(InputStream);
readInt();readLong();
DataOutputStream(OutputStream);
writeInt();writeLong();
随机读写文件:
RandomAccessFile可以对文件执行读写操作,可以将指针移动到任意位置,在任意位置读写;
使用:
RandomAccessFile(String---文件路径,String----操作模式);
读取: read(); readInt(); readDouble();
写出:write(); writeInt(); writeDouble();
移动指针:seek();
类,如:Person 在实现Serializable接口后最好加一个private static final long serialVersionUID = 1L;
每次对Person类进行改动的时候更改这个属性值,目的是为了提示更加温馨,这样就能知道这个文件升级了,
相关的文件就要重新执行了