本篇文章对日常开发中常用的Java IO场景进行整理,涉及功能有:判断目录/文件、创建目录/文件、获取文件属性、通过文件头判断文件是否为Excel、字节流/字符流读取文件、字节流/字符流写入文件、对象序列化反序列化、图片增加水印。
File
Java中File类提供了一系列方法让开发人员对于目录文件进行操作,通常是对目录文件增删:
-
判断File是文件还是目录
//===判断File是文件还是目录,目录则递归遍历
public static void isDir(File file) {
if (file.isDirectory()) {
Arrays.asList(file.listFiles()).forEach(file1 -> isDir(file1));
} else {
System.out.println("文件:" + file.getName() + ",上级目录:" + file.getParent());
}
}
-
创建目录或者文件
//===创建 目录文件
public static void createFile(File file) throws IOException {
if (!file.exists()) {
if (file.isDirectory()) {
//创建多级目录
file.mkdirs();
} else {
//判断父目录是否存在
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
//创建新文件
file.createNewFile();
}
}
}
-
删除 目录或者文件
//===删除 目录/文件
public static void deleteFile(File file) {
//删除目录必须保证目录下没有文件,否则删除失败,可通过file.listFiles()删除
boolean res = file.delete();
System.out.println("删除结果:" + res);
}
-
获取文件属性
//===获取文件属性
public static void getAttar(File file) throws IOException {
System.out.println("文件大小:" + file.length());
System.out.println("文件修改时间:" + new Date(file.lastModified()));
}
IO流
对于目录文件的操作我们可以通过File进行,但是当需要对文件内容进行操作时,就需要IO流,通过IO流我们可以实现如下业务:
-
通过文件头判断文件是否为Excel
通常我们通过文件的后缀名来判断文件类型,但是后缀名可以被恶意篡改,通过这种方式判断并不安全,通常我们可以通过文件的文件头的十六进制字符来判断文件类型(ANSI编码txt文件没有文件头),虽然文件头也可以被修改但是安全性比判断后缀要高。常见文件的文件头十六进制字符放在文章末尾
//===判断文件类型是否为Excel文件
public static boolean isExcel(InputStream inputStream) throws IOException {
//3个字节文件头
byte[] bytes = new byte[3];
inputStream.read(bytes);
String res = bytesToHexString(bytes);
System.out.println("文件头:" + res);
if ("D0CF11E0".toLowerCase().contains(res) || "504B0304".toLowerCase().contains(res)) {
return true;
}
return false;
}
private static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
//高位标记为0
int v = src[i] & 0xFF;
//十六进制字符
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
-
字节流/字符流读取文件内容
字节流是不可以重复读的,当我们读取完字节流后,inputstream不能被重复使用,所以有一个方法可以解决这个问题:mark和reset方法,但是需要markSupported判断流是否支持(FileInputStream就不支持)
//===字节流读取文件内容
private static StringBuffer readByte(InputStream inputStream) throws IOException {
StringBuffer sb = new StringBuffer();
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
byte[] bytes = new byte[bufferedInputStream.available()];
boolean support = bufferedInputStream.markSupported();
if (support)
bufferedInputStream.mark(bufferedInputStream.available());
while (bufferedInputStream.read(bytes) != -1) {
sb.append(new String(bytes));
}
if (support)
bufferedInputStream.reset();
System.out.println(sb);
inputStream.close();
return sb;
}
//===字符流读取文件内容
private static void readChar(InputStream inputStream) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
System.out.println("字符流");
StringBuffer sb = new StringBuffer();
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line + "==");
sb.append(line);
}
System.out.println();
inputStream.close();
}
-
字节流/字符流追加内容
//===字节流追加内容
private static void write(String filePath) throws IOException {
//追加,覆盖true改为false
OutputStream os = new FileOutputStream(new File(filePath), true);
String content = "每天学Java";
os.write(content.getBytes());
os.close();
}
//===字符流追加内容
private static void writeByChar(String filePath) throws IOException {
//追加,覆盖true改为false
OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(filePath, true));
String content = "\n每天学Java";
os.write(content);
os.close();
}
-
序列化和反序列化
通过序列化我们可以将对象写入磁盘中(对象需要实现Serializable接口),再通过反序列化可以拿到该对象的实例。
private static void serObject() throws IOException, ClassNotFoundException {
FileOutputStream fos = new FileOutputStream("/Users/chenlong/Documents/xcx/dream/web-project/email-project/src/main/java/com/studyjava/email/test/data.txt");
//创建写出对象的序列化流的对象,构造方法传递字节输出流,writeObject()写对象
ObjectOutputStream oos = new ObjectOutputStream(fos);
IoUtil p = new IoUtil();
oos.writeObject(p);
oos.close();
//
FileInputStream fis = new FileInputStream("/Users/chenlong/Documents/xcx/dream/web-project/email-project/src/main/java/com/studyjava/email/test/data.txt");
//创建反序列化流,readObject()读对象
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();//读对象
System.out.println(((IoUtil) obj).i);
ois.close();
}
-
图片加水印
给图片加水印是一种很常见的业务需求,通常我们可以通过Graphics2D和ImageIO实现该功能
//===图片加水印
private static void markImage(String path) throws IOException {
BufferedImage image = ImageIO.read(new File(path));
System.out.println("图片宽度:" + image.getWidth());
System.out.println("图片高度:" + image.getHeight());
Graphics2D g = image.createGraphics();
g.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
g.setFont(new Font("微软雅黑", Font.ITALIC, 40));
g.setColor(Color.BLACK);
//设置水印透明度
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.4F));
//绘制在右下角
int x = image.getWidth() - (40 * 5);
int y = image.getHeight() - 40;
//进行绘制
g.drawString("每天学Java", x, y);
g.dispose();
//输出图片
File sf = new File("/Users/chenlong/Documents/xcx/dream/web-project/email-project/src/main/java/com/studyjava/email/test/", "mark.png");
// 保存图片
ImageIO.write(image, "png", sf);
}
文件头判断
/**
* JPEG (jpg),文件头:FFD8FF
* PNG (png),文件头:89504E47
* GIF (gif),文件头:47494638
* TIFF (tif),文件头:49492A00
* Windows Bitmap (bmp),文件头:424D
* CAD (dwg),文件头:41433130
* Adobe Photoshop (psd),文件头:38425053
* Rich Text Format (rtf),文件头:7B5C727466
* XML (xml),文件头:3C3F786D6C
* HTML (html),文件头:68746D6C3E
* Email [thorough only] (eml),文件头:44656C69766572792D646174653A
* Outlook Express (dbx),文件头:CFAD12FEC5FD746F
* Outlook (pst),文件头:2142444E
* MS Word/Excel (xls.or.doc),文件头:D0CF11E0
* MS Access (mdb),文件头:5374616E64617264204A
* WordPerfect (wpd),文件头:FF575043
* Postscript (eps.or.ps),文件头:252150532D41646F6265
* Adobe Acrobat (pdf),文件头:255044462D312E
* Quicken (qdf),文件头:AC9EBD8F
* Windows Password (pwl),文件头:E3828596
* ZIP Archive / xlsx (zip/xlsx),文件头:504B0304
* RAR Archive (rar),文件头:52617221
* Wave (wav),文件头:57415645
* AVI (avi),文件头:41564920
* Real Audio (ram),文件头:2E7261FD
* Real Media (rm),文件头:2E524D46
* MPEG (mpg),文件头:000001BA
* MPEG (mpg),文件头:000001B3
* Quicktime (mov),文件头:6D6F6F76
* Windows Media (asf),文件头:3026B2758E66CF11
* MIDI (mid),文件头:4D546864
*/