JAVA I/O
一、流的分类
-
按流向分
- 输入流:将数据从存储设备读入到内存中
- 输出流:将数据从内存中存到存储设备上
-
按单位分
-
字节流:以字节为单位,可以读写所有数据
-
InputStream:字节输入流,常用有的方法:
int read()
从输入流读取数据的下一个字节。 int read(byte[] b)
从输入流读取一些字节数,并将它们存储到缓冲区 b
。int read(byte[] b, int off, int len)
从输入流读取最多 len
字节的数据到一个字节数组。void close()
关闭此输入流并释放与流相关联的任何系统资源。 -
OutputStream:字节输出流,常用有的方法:
void
write(byte[] b)将 b.length
字节从指定的字节数组写入此输出流。void write(byte[] b, int off, int len)
从指定的字节数组写入 len
个字节,从偏移off
开始输出到此输出流。void
write(int b)将指定的字节写入此输出流。 void close()
关闭此输出流并释放与此流相关联的任何系统资源。 -
文件字节流:FileInputStream/FileOutputStream
一个字节的读取方式:
/*创建文件字节流对象;传入参数为目标文件的路径*/ FileInputStream fis = new FileInputStream("C:\\Users\\18255\\Desktop\\test.txt"); //1.逐个字节读取 int data =0; while((data=fis.read()) != -1){ //当返回值为-1时,表示已经读完 System.out.print(((char)data)); } fis.close();
多个字节读取方式:
/*创建文件字节输入流对象;传入参数为目标文件的路径*/ FileInputStream fis = new FileInputStream("C:\\Users\\18255\\Desktop\\test.txt"); //多个字节读取 byte buf [] = new byte[5]; int count=0; while((count = fis.read(buf)) != -1) { System.out.print(new String(buf,0,count)); } fis.close();
写入:
/*创建文件字节输出流对象;传入参数为目标文件的路径*/ FileOutputStream fos = new FileOutputStream("C:\\Users\\18255\\Desktop\\testOut.txt"); //传入的为字节 fos.write('a'); fos.write(100); String str = "helloWorld"; fos.write(str.getBytes()); fos.close(); System.out.println("success");
-
字节缓冲流:BufferedInputStream/BufferedOutputStream
public static void main(String[] args) throws Exception { BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\18255\\Desktop\\test1.txt")); for(int i=0; i<10; i++){ bos.write("test\r\n".getBytes()); } bos.flush(); //使用flush将数据写入硬盘 bos.close(); }
-
对象流:ObjectInputStream/ObjectOutputStream
读取(反序列化):
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\18255\\Desktop\\testObject.txt")); user user = (user)ois.readObject(); System.out.println(user);
写入(序列化):
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\18255\\Desktop\\testObject.txt")); user user = new user(1,"san","nan"); oos.writeObject(user); oos.close(); System.out.println("success");
**被序列化的对象必须实现Serializable接口;**此外该类内部必须定义serialVersionUID
//例如: private static final long serialVersionUID = 155552L;
如果不添加UID则当序列化,修改类的结构,再反序列化将出错
**此外:**内部的所有属性都要可序列化(包括自定义类),默认基本数据类型可序列化;
不能序列化static、transient修饰的成员变量
-
-
字符流:以字符为单位,只能读写文本数据
-
Reader
int read()
读一个字符 int read(char[] cbuf)
将字符读入数组。 abstract int
read(char[] cbuf, int off, int len)`将字符读入数组的一部分。 int read(CharBuffer target)
尝试将字符读入指定的字符缓冲区。 -
Writer
void write(char[] cbuf)
写入一个字符数组。 abstract void write(char[] cbuf, int off, int len)
写入字符数组的一部分。 void write(int c)
写一个字符 void write(String str)
写一个字符串 void write(String str, int off, int len)
写一个字符串的一部分。 -
-
文件字符流:FileReader/FileWriter
文件字符输入流:
FileReader fr = new FileReader("C:\\Users\\18255\\Desktop\\test.txt"); char [] c = new char[2]; int count =0; while((count = fr.read(c)) != -1){ System.out.println(new String(c,0,count)); } fr.close();
文件字符输出流:
FileWriter fw = new FileWriter("C:\\Users\\18255\\Desktop\\test1.txt"); for(int i=0; i<10; i++){ fw.write("你好"); fw.flush(); } fw.close();
-
字符缓冲流:BufferedReader/BufferedWriter
字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\18255\\Desktop\\test.txt")); /* //方式一 char [] buf = new char[1024]; int count = 0; while((count = br.read(buf)) != -1){ System.out.println(new String(buf,0,count)); } */ //方式二 String line = null; while((line = br.readLine()) != null){ System.out.print(line); } br.close();
字符文件输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\18255\\Desktop\\test1.txt")); for(int i=0; i<10; i++){ bw.write("this is the test~ "); bw.newLine(); //自动写入换行 bw.flush(); } bw.close(); System.out.println("success");
-
-
按功能分
- 节点流:具有实际的传输数据的读写功能
- 过滤流:在节点流的基础上进行增强功能
二、其他
-
打印流:可以保存原有的数据样式(PrintWriter)
PrintWriter pw = new PrintWriter("C:\\Users\\18255\\Desktop\\test1.txt"); pw.println("你好"); pw.println('a'); pw.println(0.3222); pw.println(true); pw.close();
与PrintStream类似,但是PrintStream为字节流
-
转换流:InputStreamReader/OutputStreamWriter
可以将字节流转换为字符流;可设置字符的编码方式
- InputStreamReader是从字节流到字符流的桥:它读取字节,并使用指定的
charset
将其解码为字符 。 - OutputStreamWriter是字符的桥梁流以字节流:向其写入的字符编码成使用指定的字节
charset
。
public static void main(String[] args) throws Exception{ OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("C:\\Users\\18255\\Desktop\\test1.txt"),"GBK"); for(int i=0; i<10; i++){ osw.write("这是转换流的测试\r\n"); osw.flush(); } osw.close(); System.out.println("success"); System.out.println("------------------------------------"); InputStreamReader isr = new InputStreamReader(new FileInputStream("C:\\Users\\18255\\Desktop\\test1.txt"),"GBK"); char [] buf = new char[1024]; int count =0; while((count = isr.read(buf)) != -1){ System.out.println(new String(buf,0,count)); } isr.close(); }
- InputStreamReader是从字节流到字符流的桥:它读取字节,并使用指定的
三、RandomAccessFile 随机存取文件流
直接继承于Object类;
实现了DataInPut、DataInOut,即可以作输入流,又可以作输出流
RandomAccessFile(File file, String mode) 需要传入file和mode
参数 | 作用 |
---|---|
r | 只读方式打开 |
rw | 读写模式 |
rwd | 读写模式;同步文件内容的更新 |
rws | 同步文件内容和元数据的更新 |
public static void main(String[] args) {
RandomAccessFile r = null;
RandomAccessFile rw = null;
try{
r = new RandomAccessFile(new File("C:\\Users\\18255\\Desktop\\log.txt"), "r");
rw = new RandomAccessFile(new File("C:\\Users\\18255\\Desktop\\raf.txt"), "rw");
byte arr[] = new byte[100];
int len = 0;
while((len = r.read(arr)) != -1){
rw.write(arr,0,len);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (r != null){
try {
r.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (rw != null){
try {
rw.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
如果作为输出流,写出的文件不存在时,会创建文件;
如果文件已存在,则默认从头开始覆盖源文件内容;
使用seek(int pos)可以指定从pos索引处开始覆盖
四、file类
概念:文件和目录路径名的抽象表示。
文件操作:
public static void main(String[] args) throws Exception{
separator();
//FileOpe();
directoryOpe();
}
/*分隔符*/
public static void separator(){
System.out.println("路劲分隔符:"+ File.pathSeparator); //为环境变量的分隔符
System.out.println("名称分隔符:"+ File.separator); //为文件目录的分隔符
}
/*文件操作*/
public static void FileOpe() throws Exception{
//1.创建文件
File file = new File("C:\\Users\\18255\\Desktop\\fileTest.docx"); //创建文件对象
//System.out.println(file.toString()); //打印文件路劲
if(!file.exists()){ //判断文件是否村在,如果不存在则创建
boolean newFile = file.createNewFile();
System.out.println("文件创建成功");
}
//2.删除文件
//2.1直接删除
//file.delete();
//2.2使用jvm退出时删除
//file.deleteOnExit();
//3.获取文件信息
System.out.println("获取文件名称"+file.getName());
System.out.println("获取绝对路径"+file.getAbsolutePath());
System.out.println("获取父目录路径:"+file.getParent());
System.out.println(file.getUsableSpace());
System.out.println("获取文件长度:"+file.length());
//4.判断
System.out.println("是否可写"+file.canWrite());
System.out.println("是否是文件"+file.isFile());
System.out.println("是否是隐藏"+file.isHidden());
}
public static void directoryOpe(){
//1.创建文件夹
File dir = new File("C:\\Users\\18255\\Desktop\\NewDir\\aa\\cc");
if(!dir.exists()){
//dir.mkdir(); //是能创建单但目录
dir.mkdirs(); //可以创建多级目录
System.out.println("文件夹创建成功");
}
//2.删除文件夹
//2.1.直接删除
//System.out.println("删除结果"+dir.delete()); //只能删除最低级的目录,且该目录必须为空
//2.2jvm删除
//file.deleteOnExit();
//3.获取文件夹信息,基本同上(没有长度等)
//4.判断
System.out.println("是否是文件夹:"+dir.isDirectory());
//5.遍历文件夹
File file = new File("C:\\Users\\18255\\Desktop\\python");
String[] list = file.list();
for (String s : list) {
System.out.println(s);
}
}
递归遍历和删除文件夹
public static void main(String[] args) {
//listDir(new File("C:\\Users\\18255\\Desktop\\NewDir")); //目标文件夹
deleteDir(new File("C:\\Users\\18255\\Desktop\\NewDir")); //目标文件夹
}
/*递归遍历文件夹*/
public static void listDir(File f){
File[] files = f.listFiles(); //遍历文件夹,获得内容文件数组
System.out.println(f.getAbsolutePath()); //打印问价路径
if (files != null && files.length>0){ //如果数组不为空
for (File file: files) {
if (file.isDirectory()){ //判断该问价是否为文件夹,若果是进入递归;如果不是,打印文件的绝对路径
listDir(file);
}else{
System.out.println(file.getAbsolutePath());
}
}
}
}
/*递归删除文件夹*/
public static void deleteDir(File f){
File[] files = f.listFiles(); //遍历文件夹,获得内容文件数组
if (files != null && files.length>0){ //如果数组不为空
for (File file: files) {
if (file.isDirectory()){ //判断该问价是否为文件夹,若果是进入递归;如果不是,打印文件的绝对路径
deleteDir(file);
}else{
System.out.println("删除文件:"+file.delete());
}
}
}
f.delete();
}
NIO.2
jdk7发布
实例
一、复制文件(使用字节流方式)
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("C:\\Users\\18255\\Desktop\\zxy.png");
FileOutputStream fos = new FileOutputStream("C:\\Users\\18255\\Desktop\\zxyCopy.png");
int inCount = 0;
byte buf [] = new byte[1024];
while((inCount=fis.read(buf)) != -1){ //读取1k字节数据存入缓存
fos.write(buf,0,inCount); //将实际读到的字节数的数据写入文件
}
fis.close();
fos.close();
System.out.println("success");
}
二、复制文件(使用字符流方式)
只能是文本文件,图片等二进制文件不能存储
public static void main(String[] args) throws Exception {
//创建流
FileReader fr = new FileReader("C:\\Users\\18255\\Desktop\\test.txt");
FileWriter fw = new FileWriter("C:\\Users\\18255\\Desktop\\test1.txt");
//循环读取1k数据进入数组,并将数据写入硬盘
int count = 0;
char [] c= new char[1024];
while((count = fr.read(c)) != -1){
fw.write(c,0,count);
fw.flush();
}
//关闭流
fr.close();
fw.close();
System.out.println("复制完毕");
}
三、RandomAccessFile 实现插入数据
在文件索引为5的位置处插入“this is test"
public static void main(String[] args) {
RandomAccessFile r = null;
RandomAccessFile rw = null;
try {
r = new RandomAccessFile(new File("C:\\Users\\18264\\Desktop\\log1.txt"), "r");
rw = new RandomAccessFile(new File("C:\\Users\\18264\\Desktop\\log1.txt"), "rw");
StringBuilder stringBuilder = new StringBuilder((int) new File("C:\\Users\\18264\\Desktop\\log1.txt").length());
byte [] buf = new byte[20];
r.seek(5); //将光标定位置索引为5处
int len = 0;
while((len = r.read(buf)) != -1){
stringBuilder.append(new String(buf,0,len)); //将索引为5以后的数据读取并存放到StringBuilder中
}
rw.seek(5); //将写出流的光标定位在索引为5处
rw.write("this is test".getBytes()); //写入数据并覆盖原来的数据
rw.write(stringBuilder.toString().getBytes()); //将读取到的数据写入文件中,实现插入操作
} catch (Exception e) {
e.printStackTrace();
}finally {
if(r != null){
try {
r.close();
} catch (IOException e) {
e.printStackTrace();
}
if(rw != null){
try {
rw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
四、 读取文件中的行数
public static void main(String[] args) {
int count =0;
File file = new File("D:\\idea\\WorkSpace\\Mybatis01\\src");
int files= getLines(file);
System.out.println(files);
}
public static int getLines(File f){
int line = 0;
if(f.isDirectory()){ //判断传入的是否是文件夹
File[] files = f.listFiles(); //如果是,则获得该文件夹下的所有file
if(files != null && files.length >=0){
for (File file: files) { //遍历文件夹下的fiel
if(file.isFile()){ //如果是文件类型
BufferedReader br1 = null;
try {
br1 = new BufferedReader(new FileReader(file.getAbsolutePath())); //获取文件绝对路径并创建流
while(true){
String s = br1.readLine(); //读取问价中的行数,直到读取完毕返回null
if(s == null){
break;
}else{
line++;
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
br1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}else{ //如果是文件夹类型,则使用递归,遍历该文件夹下的内容
int dirs = getLines(file);
line += dirs;
}
}
}
}else{ //如果传入的不是文件夹,则直接读取
BufferedReader br2 = null;
try {
br2 = new BufferedReader(new FileReader(f.getAbsolutePath()));
while(true){
String s = br2.readLine();
if(s == null){
break;
}else{
line++;
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
br2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return line; //返回该file的行数
}