目录
1、 概述
想要对数据进行持久化等操作,就需要一些技术完成一些其他设备上的数据操作,就需要IO技术。
java中提供了IO技术的操作方式。最终依赖于操作系统。
2、File的出现
数据最终持久化到硬盘上,体现就是文件。
文件有名称、大小、创建时间。。。
既然有这么多信息,最好将其封装成对象,操作更加容易。
类FILE:文件和目录路径名的抽象表示形式。
2.1 File类中的构造函数&分隔符
package io_learning;
import java.io.File;
import java.io.FileReader;
public class file_learn {
public static void main(String[] args) {
/*
File类的构造函数
如何创建文件对象
*/
String path = "F:/javaworkspace/1.txt";
File f = new File(path); //将1.txt文件封装成对象,注意:也可以封装不存在的文件和文件夹变成对象。
System.out.println(f);
File f2 = new File("F:\\javaworkspace","1.txt");
System.out.println(f2);
File dir = new File("F:\\javaworkspace"); // 将File父目录封装成一个对象
File f3 = new File(dir,"1.txt");
System.out.println(f3);
File f4 = new File("F:"+File.separator+"javawrokspace","1.txt");
System.out.println(f4);
}
}
2.2 File类中的方法:获取
package IO;
import javafx.scene.input.DataFormat;
import java.io.File;
import java.text.DateFormat;
import java.util.Date;
public class file_method_demo {
public static void main(String[] args) {
/*
file类的方法演示
获取文件的信息,名称、大小、时间等
*/
File file = new File("/home/leo/javatest.txt");
String filename = file.getName();
String path = file.getAbsolutePath();
long size = file.length();
long time = file.lastModified();
//毫秒值--date--格式化--字符文本
String str_data = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG).format(new Date(time));
System.out.println(str_data);
System.out.println(filename+path+size+time);
}
}
2.3 File类中的方法:文件以及文件夹的删除创建存在
package IO;
import java.io.File;
import java.io.IOException;
public class file_method_demo2 {
public static void main(String[] args) throws IOException {
/*
file类中的方法2
对文件或者文件夹进行操作
*/
File file = new File("/home/leo/file.txt");
/*
创建文件,如果文件不存在,创建true
如果文件存在,创建false
如果路径错误,存在IO异常
*/
boolean b1 = file.createNewFile();
System.out.println("b1="+b1);
/*
删除
*/
boolean b2 = file.delete(); //不去回收站,慎用
System.out.println("b2="+b2);
/*
判断文件是否存在
*/
boolean b3 = file.exists();
System.out.println("b3="+b3);
/*
对目录创建,删除,判断
*/
File dir = new File("/home/leo/javatest");
boolean b4= dir.mkdir();
//创建多级目录为mkdirs
boolean b5= dir.delete(); //删除目录时,如果目录中有内容,则无法直接删除。要保证目录为空,才可以删除
//判断是否为目录或者文件,要判断文件是否为文件或者目录,首先要会自动判断文件是否存在,如果不存在,则为false
file.isFile();
dir.isDirectory();
}
}
2.4 listFiles()方法
获取目录下的当前文件以及文件对象
package IO;
import java.io.File;
public class file_method_demo3 {
public static void main(String[] args) {
/*
需求:对给定的目录获取全部的内容
*/
File dir = new File("/home/leo");
String[] names = dir.list(); //获取目录下的当前文件以及文件夹的名称
for (String name : names) {
System.out.println(name);
}
File[] files = dir.listFiles(); //获取目录下的当前文件以及文件夹对象
for(File file : files){
System.out.println(file);
}
}
}
文件名过滤器
第一种方法,过滤指定文件名的文件
需要实现接口,然后再对对象进行操作
package IO;
import java.io.File;
import java.io.FilenameFilter;
public class filenamefilter implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".java");
}
}
File file = new File("/home/leo/IdeaProjects/java300/src/hashset");
File[] files = file.listFiles(new filenamefilter());
第二种方法
在接口中定义需要过滤的文件名
package IO;
import java.io.File;
import java.io.FilenameFilter;
/*
用于过滤指定扩展名的文件
*/
public class filenamefilter_2 implements FilenameFilter {
private String suffix;
public filenamefilter_2(String suffix){
super();
this.suffix = suffix;
}
@Override
public boolean accept(File dir, String name) {
return name.endsWith(suffix);
}
}
File[] files1 = file.listFiles(new filenamefilter_2(".java"));
文件过滤器
如果想要目录
package IO;
import java.io.File;
import java.io.FileFilter;
public class filefilter implements FileFilter {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
}
File[] files2 = file.listFiles(new filefilter());
2.5 练习-获取所有子目录中的内容
package IO;
import java.io.File;
public class file_method_practice {
public static void listAll(File dir){//dir接受目录以及子目录
System.out.println("dir="+dir);
File[] file = dir.listFiles();
for(File file1:file){
if(file1.isDirectory()){
listAll(file1);
}else {
System.out.println("file="+file1.getName());
}
}
}
public static void main(String[] args) {
/*
File类的listFiles()列出当前目录下的文件以及文件夹
需求:列出当前目录下子目录的所有内容
1、在遍历当前目录时,会获取到当前的所有文件以及文件夹
2、要遍历子目录,那就需要对获取到的当前的file对象进行判断,只有目录才可以作为子目录进行继续遍历
*/
File dir = new File("/home/leo/IdeaProjects/hello_world/");
listAll(dir);
}
}
2.6 文件队列
如果不用递归呢?也就不用担心溢出的问题
思路:把所有文件夹都放在一个容器里面存起来。
容器只要是队列就可以解决问题
package IO;
import java.io.File;
import java.util.LinkedList;
public class getall_file {
/*
遍历文件夹,不用递归
1、通过对每一个目录进行for循环,但是目录层级很多,for会死掉。
2、每遍历到一个目录,不对其进行遍历,而是临时存储起来
相当于把所有目录,无论同级不同级,只要是目录,都存储起来,遍历容器时,取到的就是目录,然后对目录进行遍历
3、从容器中取到目录遍历时发现内部还有目录,一样将这些目录存储到容器中
4、只要不断遍历容器就可以了
*/
public static void main(String[] args) {
File dir = new File("/home/leo/IdeaProjects/hello_world");
Queue<File> queue = new Queue<File>();
//1、对dir进行当前目录的遍历
File[] files = dir.listFiles();
for(File file:files){
//2、如果有子目录,存储到队列中
if(file.isDirectory()){
queue.add(file);
}else{
System.out.println(file.getName());
}
}
System.out.println("--------------------------");
//遍历队列容器,因为子目录都在队列中
while (!queue.isEmpty()){
File subdir = queue.get(); //从队列中取出子目录
System.out.println(subdir.getName());
//4 遍历子目录
File[] subdirs = subdir.listFiles();
for(File subdirss:subdirs){
if(subdirss.isDirectory()){ //如果子目录中还有子目录,继续存队列
queue.add(subdirss);
}else {
System.out.println(subdirss.getName());
}
}
}
}
}
//队列结构
class Queue<E>{
private LinkedList<E> list;
/*
提供一个构造队列对象的构造器
*/
public Queue(){
list = new LinkedList<E>();
}
/*
添加元素的方法
*/
public void add(E obj){
list.addFirst(obj);
}
/*
获取的方法
*/
public E get(){
return list.removeLast();
}
/*
判断队列是否有元素
*/
public boolean isEmpty(){
return list.isEmpty();
}
}
3 字节输出流
3.1 数据写入到文件中
需求:往文件中写入数据
outputstream:输出字节流的超类
1、操作的数据都是字节
2、定义了输出字节流的基本共性功能
3、输出流中定义的都是写write方法
4、操作字节数组,操作单个字节
5、子类有规律,所有子类名称的后缀都是父类名,前缀名就是这个流对象的功能。
想要操作文件:Fileoutputstream
package IO_bytestream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class fileoutputstream {
/*
需求:将数据写入文件中
*/
public static void main(String[] args) throws IOException {
File dir = new File("/home/leo/javatest.txt");
//创建用于操作文件的字节流输出对象,一创建就必须明确数据存储目的地
//输出流目的如果是文件,那么会自动创建此文件。如果文件存在,则覆盖。
FileOutputStream fos = new FileOutputStream(dir);
//调用父类中的write方法
byte[] bytes = "abcde".getBytes();
fos.write(bytes);
//记得用完之后关掉
fos.close();
}
}
3.2 续写、换行
FileOutputStream(File file,boolean append) 续写。
package IO_bytestream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class demo2 {
public static void main(String[] args) throws IOException {
/*
需求:将数据写入文件中。续写到已有文件中
*/
//FileOutputStream(File file,boolean append) 续写。
File file = new File("/home/leo/javatest.txt");
FileOutputStream fos = new FileOutputStream(file,true);
byte[] b = "append".getBytes();
fos.write(b);
fos.close();
}
}
新需求:在下一行写入新数据
package IO_bytestream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class demo2 {
public static void main(String[] args) throws IOException {
/*
需求:将数据写入文件中。续写到已有文件中
*/
//FileOutputStream(File file,boolean append) 续写。
File file = new File("/home/leo/javatest.txt");
FileOutputStream fos = new FileOutputStream(file,true);
byte[] b = "\r\nappend".getBytes();
fos.write(b);
fos.close();
}
}
package IO_bytestream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class demo2 {
public static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static void main(String[] args) throws IOException {
/*
需求:将数据写入文件中。续写到已有文件中
*/
//FileOutputStream(File file,boolean append) 续写。
File file = new File("/home/leo/javatest.txt");
FileOutputStream fos = new FileOutputStream(file,true);
String str = LINE_SEPARATOR+"append";
byte[] b = str.getBytes();
fos.write(b);
fos.close();
}
}
3.3 IO异常的处理
package IO_bytestream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileNotfoundExceptionDemo {
public static void main(String[] args) {
File file = new File("k:/home/leo/javatest.txt");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write("abcde".getBytes());
}catch (IOException e){
//这个catch如果没有处理,则不需要写
System.out.println(e.toString());
}finally {
try {
fos.close();
} catch (IOException e) {
throw new RuntimeException("runtime exception");
}
}
}
}
fos为空,出现空指针异常。因为k盘不存在,所以创建失败,创建失败file对象就为空。
所以要判断,如果fos不为空,才有资格关闭
package IO_bytestream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileNotfoundExceptionDemo {
public static void main(String[] args) {
File file = new File("k:/home/leo/javatest.txt");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write("abcde".getBytes());
}catch (IOException e){
//这个catch如果没有处理,则不需要写
System.out.println(e.toString());
}finally {
try {
if(fos!=null){
fos.close();
}
} catch (IOException e) {
throw new RuntimeException("runtime exception");
}
}
}
}
4 字节输入流
4.1 读取数据read()方法
需求:读取文件中的数据,显示在屏幕上
找到类InputStream
InputStream:此类是表示字节输入流的所有类的超类。
常见功能:
1、int read() 读取下一个字节并返回,没有字节返回-1.
注意:每次读取的是下一个字节。
package IO_bytestream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class Fileinputstream {
public static void main(String[] args) throws IOException {
File file = new File("/home/leo/javatest.txt");
//和数据进行关联
FileInputStream fis= new FileInputStream(file);
//使用read一次读取一个字节
int ch1 = fis.read();
//使用read读取下一个字节
int ch2 = fis.read();
System.out.println("ch1 = "+(char)ch1);
System.out.println("ch2 = "+(char)ch2);
fis.close();
}
}
如果要一次读完呢?
package IO_bytestream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class Fileinputstream {
public static void main(String[] args) throws IOException {
File file = new File("/home/leo/javatest.txt");
//和数据进行关联
FileInputStream fis= new FileInputStream(file);
int ch;
//使用read一次读取一个字节
while ((ch=fis.read())!= -1){
System.out.println(ch);
}
fis.close();
}
}
2、int read(byte[] b); 读取一定数量的字节,并存储到缓冲区b中,返回读到的字节数。
构造方法,在构造时一定要明确文件。
用于读取文件的字节输入流对象InputStream。
package IO_bytestream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class FileinputstreamDemo2 {
public static void main(String[] args) throws IOException {
File file = new File("/home/leo/javatest.txt");
FileInputStream fis = new FileInputStream(file);
byte[] buf = new byte[1024] ;
//读取字节并把字节存储到buf字节数组中
int len1=fis.read(buf);
System.out.println(new String(buf));
System.out.println(len1);
fis.close();
}
}
第二种方法好,因为效率高。数组长度1024的整数倍合适。
4.2 字节流-复制文件
package IO_bytestream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyFileTest {
/*
练习:复制文件。
思路:读取一个已有的数据,并将这些读到的数据写入到另一个文件中
*/
public static void main(String[] args) throws IOException {
//1、明确源和目的
File src = new File("/home/leo/javatest.txt");
File dest = new File("/home/leo/javatest2.txt");
//2、读取一个已有的数据
FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest);
int ch = 0;
while((ch = fis.read())!=-1){
fos.write(ch);
}
fis.close();
fos.close();
System.out.println("done!");
}
}
使用字节数组的方式
package IO_bytestream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyFileTest2 {
public static void main(String[] args) throws IOException {
File src = new File("/home/leo/javatest.txt");
File dest = new File("/home/leo/javatest3.txt");
FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest);
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes))!= -1){
fos.write(bytes,0,len);
}
fis.close();
fos.close();
System.out.println("done!");
}
}
4.3 available()方法
api介绍:返回此输入流下一个方法调用可以不受阻塞地从输入流读取(或跳过)的估计字节数
方法用得着,但是要小心。
可以返回文件的字节数。
所以可以用来估计缓冲区数组的大小。
package IO_bytestream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class availiable_method {
public static void main(String[] args) throws IOException {
/*
字节输入流有这么个方法叫available();
*/
//关联文件
FileInputStream fis = new FileInputStream("/home/leo/javatest.txt");
System.out.println(fis.available());
//可以返回文件的大小
byte[] buf = new byte[fis.available()]; //定义了一个刚刚好的数组
fis.read(buf);
System.out.println(new String(buf));
fis.close();
}
}
但是,这个方法,尽量不要用在这里。数组长度还是要按照1024的整数倍
为什么?
如果文件过大,容易溢出,所以建议缓冲区的长度还是1024的整数倍。
4.4 练习,删除一个带有文件的目录
package IO;
import java.io.File;
public class io_test {
/*
请删除一个带有内容的目录
思路:
1、删除一个带有内容的目录,原理就是,必须从里往外删。
2、到底有多少级目录不确定,用递归。
*/
public static void main(String[] args) {
File file = new File("E:\\javatest");
removeDir(file);
}
/*
删除一个目录
*/
public static void removeDir(File dir){
//列出当前目录下的文件以及文件夹
File[] files = dir.listFiles();
for(File file:files){
//对遍历到的file对象判断是否为目录
if(file.isDirectory()){
removeDir(file);
}else {
file.delete();
}
}
System.out.println(dir.delete());
}
}
4.5 练习-学生总分信息存储
package IO;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;
public class ioTest2 {
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
/*
学生总分信息存储
将学生对象 (姓名,语文分数,数学分数,英语分数,总分)按照总分从高到低排序
并将姓名和从高到低总分写入文件中
1、描述学生
2、既然要按照总分从高到底排序,学生都要存储,集合。TreeSet。
3、将具体信息保存到文件中。
操作文件,持久化存储,设计到IO技术。所以写入,输出流。
*/
public static void main(String[] args) {
Set<Student> set = new TreeSet<Student>(Collections.reverseOrder());
set.add(new Student("李四",20,20,20));
set.add(new Student("旺财",10,10,20));
set.add(new Student("小明",60,30,80));
set.add(new Student("小红",80,90,80));
set.add(new Student("小强",20,70,20));
File destFile = new File("F:\\javatest\\student.txt");
try {
write2File(set,destFile);
} catch (IOException e) {
e.printStackTrace();
}
for(Student sto : set){
System.out.println(sto);
}
}
public static void write2File(Set<Student> set , File destFile) throws IOException{
//创建一个输出流对象和目的文件关联,并创建目的文件 Outputstream操作文件Fileoutputstream
FileOutputStream fos = null;
try{
fos = new FileOutputStream(destFile);
for(Student stu:set){
String info = stu.getName()+"\t"+stu.getTotal()+LINE_SEPARATOR;
fos.write(info.getBytes());
}
}finally {
//遍历集合中的对象数据,将数据写入到指定文件中
if(fos!= null){
try {
fos.close();
}catch (IOException e){
throw new RuntimeException("系统资源关闭失败");
}
}
}
}
}
class Student implements Comparable<Student>{
private String name;
private int cn,en,math,total;
public Student(String name,int cn,int en,int math){
super();
this.name = name;
this.cn = cn;
this.en = en;
this.math = math;
this.total = cn + en + math ;
}
@Override
public int compareTo(Student o){
int temp = this.total - o.total;
return temp==0?this.name.compareTo(o.name):temp;
}
public Student(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getCn() {
return cn;
}
public void setCn(int cn) {
this.cn = cn;
}
public int getEn() {
return en;
}
public void setEn(int en) {
this.en = en;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
@Override
public String toString(){
return "Student [name = "+name+",sum = "+total+"]";
}
}
4.6 练习-文件清单
package IO;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class io_test2 {
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static void main(String[] args) {
/*
获取指定目录下所有的.java文件(包含子目录中的)
并将这些java文件的绝对路径写入到一个文件中
建议一个java文件清单列表
思路:1、一看到包含子目录:递归
2、写数据到文件,输出流
3、继续分析,只要.java,需要过滤器
4、满足过滤条件的文件,可能非常多,最好先进行存储。
*/
File dir = new File("F:\\java workspace");
//明确一个过滤器
FileFilter fileFilter = new FileFilterByjava(".java");
//符合过滤器文件的条件有很多,最好先存储起来,然后再进行操作。
List<File> list = new ArrayList<File>();
//获取指定文件清单
getFileList(dir,fileFilter,list);
File destFile = new File("F:\\javatest\\list.txt");
try {
write2File(list,destFile);
} catch (IOException e) {
e.printStackTrace();
}
}
//将集合中文件的绝对路径,写到文件中
private static void write2File(List<File> list, File destFile) throws IOException{
FileOutputStream fos = null;
//或者一次写一个字符串
BufferedOutputStream bufos = null;
try {
fos = new FileOutputStream(destFile);
bufos = new BufferedOutputStream(fos);
for (File list1 : list) {
String separator = list1.getAbsolutePath() + LINE_SEPARATOR;
bufos.write(separator.getBytes());
bufos.flush(); //每写一个绝对路径就刷新一次
}
}finally {
if(bufos != null){
try {
fos.close();
}catch (IOException e ){
throw new RuntimeException("关闭失败");
}
}
}
}
private static void getFileList(File dir, FileFilter fileFilter,List<File> list) {
File[] files = dir.listFiles();
for(File file:files){
if(file.isDirectory()){
getFileList(file,fileFilter,list);
}else {
//如果是文件,那么传递到过滤器中去过滤,将满足条件的存储起来
if (fileFilter.accept(file)){
list.add(file);
System.out.println(file);
}
}
}
}
}