转换流
字节流和字符流进行相互转换
OutputStreamWriter:将字节输出流转化为字符输出流
InputStreamReader:将字节输入流转化为字符输出流
使用示例:
//创建文件字节输出流(节点流/低级流)
FileOutputStream os = new FileOutputStream(path);
//将字节输出流转换为字符输出流(高级流/过滤流)
OutputStreamWriter osw = new OutputStreamWriter(os);
InputStreamReader isr = new InputStreamReader( new FileInputStream(path)) ;
通过源码查看实现
public class OutputStreamWriter extends Writer {
//转换器,将beyte字节转换为char字符
private final StreamEncoder se;
public OutputStreamWriter(OutputStream out) {
super(out);
try {
se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}
}
public class InputStreamReader extends Reader {
private final StreamDecoder sd;
public InputStreamReader(InputStream in) {
super(in);
try {
sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}
}
转换流称之为处理流,即高级流
InputStreamReader
Reader和InputStream的关系
普通的Reader实现实际上是基于InputStream构造的,因为Reader需要从InputStream中读取字节流(byte),然后根据编码设置,在转化为char就可以实现字符流,在转换流中持有一个byte到char的转换器,那么如果我们已经有了一个InputStream想把它转化为Reader,是完全可以的,InputStreamReader功能就类似于一个转换器。可以把任何的InputStream转换为Reader
缓冲流
提高IO读写速度
缓冲流分为:字节缓冲流和字符缓冲流
字节缓冲流:BufferInputStream,BufferOutputStream
字符缓冲流:BufferReader,BufferWriter
以字符缓冲流为例介绍:
除了提供缓冲功能,还提供新的方法
在字符缓冲输出流中:bufferWriter
void newLine()://换行操作,写入一个换行符,根据系统添加换行符 '\r\n'
public static void testBufferReaderWriter(String path) {
try {
BufferedWriter fw = new BufferedWriter(new FileWriter(path));
fw.write("hello");
//换行操作,写入一个换行符,根据系统添加换行符 '\r\n'
fw.newLine();
fw.write("xuzhi");
fw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
在字符缓冲输入流中:BufferReader;
String readLine() ;//读取一个文本行,包含该内容的字符串,不包含任何终止符,如果到达流末尾,返回null
BufferedReader br = new BufferedReader(new FileReader(path));
//String readLine() 读取一个文本行,包含该内容的字符串,不包含任何终止符,如果到达流末尾,返回null
String msg = null;
while((msg = br.readLine()) != null){
System.out.println(msg);
}
RandomAccessFile的使用
构造函数说明
RandomAccessFile(String name, String mode)
RandomAccessFile(File file, String mode)
RandomAccessFile构造函数有两个参数,第一个参数都是表示文件路径,只是类型不同。除此之外第二个参数指定的是mode,该参数是用来指定RandomAccessFile访问模式,有4种值
- “r”:以只读的方式打开,如果调用write方法会抛出异常
- “rw”:打开以便读取和写入
- “rws”:打开以方便读和写,相对于"rw","rws"还要对文件的内容和元数据每个更新操作都要同步写入存储设备
- “rwd”:打开以方便读和写,相对于"rw","rwd"还要对文件的内容每个更新操作都要同步写入存储设备
说明:
- RandomAccessFile是IO体系中功能最丰富的文件内容访问类,即可以读取文件内容,也可以向文件中写入内容。而其他的流都是有方向,要么是读取的流,要么是写操作的流;
- RandomAccessFile的程序可以直接跳到文件的任意位置来读取和写入内容,该对象的文件记录指针位于文件头(在0位置),当读/写n个字节后,文件记录指针也会向后移动n个字节,除此之外, RandomAccessFile可以自由移动指针,即可以向前,也可以向后。
特殊的方法
long getFilePointer();//返回文件指针的位置
void seek(long pos);//将文件指针移动到指定的pos位置 在内容范围内 pos <= lenght
public class TestRandomAccessFile {
/**
* @param path:指定文件
* @param index:指定文件中内容
* @param content:追加的内容
*/
public static void appendContent(String path, Integer index, String content) {
try {
File file = new File(path);
if (!file.exists()) {
System.out.println("指定文件不存在");
return;
}
RandomAccessFile raf = new RandomAccessFile(path, "rws");
//校验插入位置是否合法
if (index > raf.length()) {
System.out.println("插入数据位置越界");
return;
}
//临时文件存储位置
String tmpPath = file.getParent() + File.separator + "tmp.txt";
File tmpfile = new File(tmpPath);
//在程序退出时删除
tmpfile.deleteOnExit();
RandomAccessFile tmpStream = new RandomAccessFile(tmpfile, "rw");
//让文件指针移动到指定位置
raf.seek(index);
//循环读取内容,将指定位置之后数据读取
byte[] bytes = new byte[100];
int len;
while ((len = raf.read(bytes)) != -1) {
tmpStream.write(bytes, 0, len);
}
//让文件指针再次移动到指定位置
raf.seek(index);
//将追加内容写入
raf.write(content.getBytes());
//将临时文件从头开始读
tmpStream.seek(0);
//将暂存之临时文件的内容获取写入
while ((len = tmpStream.read(bytes)) != -1) {
raf.write(bytes, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String path = "C:/Users/lyy0721/Desktop/work.txt";
appendContent(path,3,"lyy");
}
}
Java8新特性
Lambda表达式
lambda表达式是匿名函数,没有一个名字的函数。
Lambda表达式使用:
对于集合map的遍历,传统的遍历方式
Hashtable<String,String> hashTable = new Hashtable <String,String>();
hashTable.put("k1","v1");
hashTable.put("k2","v2");
hashTable.put("k3","v3");
hashTable.put("k4","v4");
Iterator<Map.Entry<String,String>> iterator = hashMap.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String,String> entry = iterator.next();
System.out.println(entry.getKey()+":"+entry.getValue());
}
注意:lambda表达式是在Java8之后才有的,必须JDK是在Java8之后才能看到lambda
//通过lambda遍历
hashTable.forEach((k,v) ->{
System.out.println(k+":"+v);
});
表示是 ()->{}
lambda表达式特点
- 一个lambda表达式可以有零个或者是多个参数
- 参数的类型可以明确给定,也可以不给定,可以上下文进行推断,例如(int a) 和(a)效果是一样
- 所有的参数都包含在圆括号中,参数可以通过逗号隔开,例如(k,v)或者(String k,String v)
- 圆括号代表参数级也可以为空,例如:()->42
- 当只有一个参数时,且类型可以推导时,圆括号()也可以省略,例如:a-> return a*a
- lambda表达式主体可以是零条或者是多条
- 如果lambda表达式的主体只有一条,花括号{}都可以省略,匿名函数的返回类型需要与该主题表达式一致
- 如果lambda表达式的主体有多条,则表达式必须包含在花括号{}中
lambda表达式可以简化代码,同时也减少代码的可读性