工具类批量修改照片的名字

同步照片的时候,发现照片名字不规则 。 以下类产生的格式 2014-04-20 09.44.43.jpg  
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;


/*******************************************************************************
 * 
 * 读出数码图片中的拍照时间
 * 
 * 
 * 原理:
 * 
 * 1、由于数码图片的拍照时间可以直接从图片中搜索到,所以本例不需要分析EXIF的格式。
 * 
 * 2、正常的(Normal)数码图片,会有三处到四处的时间,其中第二、第三处固定在一起,
 * 
 * 第二处是图片拍摄时间,第三处是图片存储时间,一般两者相同,他们之间用NULL值
 * 
 * 分隔(ASCII值为0),如下:
 * 
 * 2001:01:02 12:23:56[NULL]2001:01:02 12:23:56[NULL] 2001/01/02
 * 12:23[NULL]2001/01/02 12:23[NULL]
 * 
 * 两者位置不定,但格式好查找,八个冒号,两个空格,两个NULL值,其余为数字。
 * 
 * 不用考虑01:09:34被压缩为1:9:34这样的特例,见EXIF2.1规范关于时间的三段:
 * 
 * 1. DateTime(第一处,修改时间)
 * 
 * The date and time of image creation. In this standard it is the date and time
 * 
 * the file was changed.
 * 
 * The format is "YYYY:MM:DD HH:MM:SS" with time shown in 24-hour format, and
 * 
 * the date and time separated by one blank character [20.H].
 * 
 * When the date and time are unknown, all the character spaces except colons
 * (":")
 * 
 * may be filled with blank characters, or else the Interoperability field may
 * be
 * 
 * filled with blank characters.
 * 
 * The character string length is 20 bytes including NULL for termination.
 * 
 * When the field is left blank, it is treated as unknown.
 * 
 * Tag = 306 (132.H)
 * 
 * Type = ASCII
 * 
 * Count = 20
 * 
 * Default = none
 * 
 * 2. DateTimeOriginal(第二处,拍摄时间)
 * 
 * The date and time when the original image data was generated. For a DSC the
 * 
 * date and time the picture was taken are recorded.
 * 
 * The format is "YYYY:MM:DD HH:MM:SS" with time shown in 24-hour format, and
 * 
 * the date and time separated by one blank character [20.H].
 * 
 * When the date and time are unknown, all the character spaces except colons
 * (":")
 * 
 * may be filled with blank characters, or else the Interoperability field may
 * be
 * 
 * filled with blank characters.
 * 
 * The character string length is 20 bytes including NULL for termination.
 * 
 * When the field is left blank, it is treated as unknown.
 * 
 * Tag = 36867 (9003.H)
 * 
 * Type = ASCII
 * 
 * Count = 20
 * 
 * Default = none
 * 
 * 3. DateTimeDigitized(第三处,存储时间)
 * 
 * The date and time when the image was stored as digital data. If, for example,
 * 
 * an image was captured by DSC and at the same time the file was recorded, then
 * 
 * the DateTimeOriginal and DateTimeDigitized will have the same contents.
 * 
 * The format is "YYYY:MM:DD HH:MM:SS" with time shown in 24-hour format, and
 * 
 * the date and time separated by one blank character [20.H].
 * 
 * When the date and time are unknown, all the character spaces except colons
 * (":")
 * 
 * may be filled with blank characters, or else the Interoperability field may
 * be
 * 
 * filled with blank characters.
 * 
 * The character string length is 20 bytes including NULL for termination.
 * 
 * When the field is left blank, it is treated as unknown.
 * 
 * Tag = 36868 (9004.H)
 * 
 * Type = ASCII
 * 
 * Count = 20
 * 
 * Default = none
 * 
 * 3、特别的(Special)相机,如富士系列FUJIFILM,使用XML格式记录EXIF,时间格式如下:
 * 
 * 2006-12-24T12:33:08+08:00
 * 
 * 对比正常的(Normal)相片,我们发现两者格式很类似:
 * 
 * 2006:12:24 12:33:08 Normal
 * 
 * 2006-12-24T12:33:08 Special
 * 
 * 
 * 另外:
 * 
 * 1、由于本人测试的*.tif和*.tiff图片是由*.jpg通过ACDSee转换的,所以可能不准。
 * 
 * 2、当然,网上有现成的包可供利用,详细方法请自行搜索,以下是包下载地址:
 * 
 * http://www.drewnoakes.com/code/exif/releases/metadata-extractor-2.2.0.jar
 * 
 * 3、此例没有按照标准的Java规范格式化。
 * 
 * 4、开源的目的只有一个:我为人人,人人为我,欢迎开源!
 * 
 * 
 * Version: 1.10
 * 
 * Author: NeedJava
 * 
 * E-Mail: [email protected]
 * 
 * Modified: 2007.08.16/2007.08.29/2007.09.28/2010.03.15
 * 
 * 
 * 你可以使用此程序于任何地方,但请保留程序作者及注释的完整。如果你改进了程序,
 * 
 * 请在原作者后添加姓名,如:Author: NeedJava/Jack/Mike,版本及修改时间同理。
 * 
 ******************************************************************************/
public final class PictureRenamer {
	public static final int FILE_MIN_LENGTH = 102400; // 查找文件的最小字节数


	public static final int SEQUENCE_LENGTH = 3; // 默认图片序列号的长度


	private static final char[] SUFFIX_JPG = { '.', 'j', 'p', 'g' }; // { 46,
																		// 106,
																		// 112,
																		// 103 }


	private static final char[] SUFFIX_JPEG = { '.', 'j', 'p', 'e', 'g' }; // {
																			// 46,
																			// 106,
																			// 112,
																			// 101,
																			// 103
																			// }


	private static final char[] SUFFIX_JPE = { '.', 'j', 'p', 'e' }; // { 46,
																		// 106,
																		// 112,
																		// 101 }


	private static final char[] SUFFIX_JFIF = { '.', 'j', 'f', 'i', 'f' }; // {
																			// 46,
																			// 106,
																			// 102,
																			// 105,
																			// 102
																			// }


	private static final char[] SUFFIX_TIF = { '.', 't', 'i', 'f' }; // { 46,
																		// 116,
																		// 105,
																		// 102 }


	private static final char[] SUFFIX_TIFF = { '.', 't', 'i', 'f', 'f' }; // {
																			// 46,
																			// 116,
																			// 105,
																			// 102,
																			// 102
																			// }


	private static final char PRI_SEPARATOR = '-'; // 45 主要分隔符
	
	private static final char PRI_SUB_SEPARATOR = '.'; // 32 次要分隔符


	private static final char SUB_SEPARATOR = ' '; // 32 次要分隔符


	private int minLength; // 处理图片的最小字节数


	private int sequenceLength; // 图片序列号的长度


	private int totalFolders; // 文件夹总数


	private int totalFiles; // 文件总数


	private int totalPictures; // 图片总数


	private int parsedPictures; // 含有有效时间的图片总数


	private int renamedPictures; // 成功修改名称的图片总数


	/***************************************************************************
	 * 
	 * 构造函数,默认使用当前路径,不搜索100KB以下图片
	 * 
	 * 由ACDSee剪裁生成的图片,仍然保留着详细的EXIF信息,哪怕图片只有一个像素,
	 * 
	 * 但是这样的图片有意义吗?我觉得既然是数码相片,至少应该大于100KB。
	 * 
	 * 当图片大小小于一定值时不予理会,当然你可以取消这样的限制
	 * 
	 **************************************************************************/
	public PictureRenamer() {
		this(FILE_MIN_LENGTH, SEQUENCE_LENGTH);
	}


	public PictureRenamer(int minLength, int sequenceLength) {
		this.totalFolders = 0;


		this.totalFiles = 0;


		this.totalPictures = 0;


		this.parsedPictures = 0;


		this.renamedPictures = 0;


		this.minLength = (minLength < 0 ? FILE_MIN_LENGTH : minLength);


		this.sequenceLength = (sequenceLength < 0 ? SEQUENCE_LENGTH
				: sequenceLength);
	}


	/***************************************************************************
	 * 
	 * 列出当前目录下的文件列表,包括文件和文件夹
	 * 
	 * Windows操作系统中,File类中关键是抽象类FileSystem,而FileSystem关键如下:
	 * 
	 * public static native FileSystem getFileSystem();
	 * 
	 * 实际返回的是子类Win32FileSystem
	 * 
	 **************************************************************************/
	public final void listPictures(File parent, String fileName)
			throws FileNotFoundException, IOException {
		File file = new File(parent, fileName);


		if (file.isDirectory()) {
			totalFolders++;


			String[] children = file.list();
			if (children == null) {
				return;
			}


			// java.util.Arrays.sort( children ); //没必要排序


			for (int i = 0; i < children.length; i++) {
				listPictures(file, children[i]);
			}
		} else {
			totalFiles++;


			char[] suffix = getPictureSuffix(fileName);
			if (suffix == null) {
				return;
			}


			if (suffix.length > 0) // 当前文件是图片
			{
				totalPictures++;


				// logger( "/r/nProcess/t[" + file.getPath() + "]", false );


				// TODO:增加观察者,代替logger,使用线程wait和notify


				// TODO:判断是否是格式化过的图片,如果是,就退出,或者强制修改。XXXX:放弃这个,因为AcdSee处理的经常是错的


				long length = file.length();
				if (length < minLength) { /*
										 * logger( length + " is less than " +
										 * minLength + " bytes, Ignore.", false
										 * );
										 */
					return;
				}


				char[] datetime = getPictureDateTime(file);
				if (datetime == null) {
					return;
				} // fileName.substring( 0, fileName.length() - suffix.length
					// ).toCharArray();


				if (datetime.length == 19/**/) // 注释掉这行,就可以按序列号重新排序命名
				{
					parsedPictures++;


					String newName = rename(parent, file, fileName, datetime,
							suffix, 0/*-1*/); // 检查新文件名是否被占用,如果没被占用,就修改名称


					if (newName == null) { /*
											 * logger( "Rename/t[" + newName +
											 * "]/tFailed", false );
											 */
						return;
					}


					renamedPictures++;


					// logger( "Rename/t[" + newName + "]/tSucceed", false );
				}
			}
		}
	}


	/***************************************************************************
	 * 
	 * 根据后缀名判断是否是有效的图片,并且返回小写的后缀名
	 * 
	 * lastIndexOf()和substring()可以完成,但是我还想把后缀名小写,并且减少无谓循环
	 * 
	 **************************************************************************/
	private final char[] getPictureSuffix(String fileName) {
		if (fileName == null) {
			return null;
		}


		int pointer = fileName.length() - 1;


		if (pointer > 2) // 可能存在“.jpg”这样的文件,即文件名只有4个字符
		{
			char c = fileName.charAt(pointer--);


			if (c == 'g' || c == 'G') // 1
			{
				c = fileName.charAt(pointer--);


				if (c == 'p' || c == 'P') // 2
				{
					c = fileName.charAt(pointer--);


					if ((c == 'j' || c == 'J') && (pointer > -1)) // 3
					{
						if (fileName.charAt(pointer) == '.') {
							return SUFFIX_JPG;
						} // 4
					}
				} else if (c == 'e' || c == 'E') // 2
				{
					c = fileName.charAt(pointer--);


					if (c == 'p' || c == 'P') // 3
					{
						c = fileName.charAt(pointer--);


						if ((c == 'j' || c == 'J') && (pointer > -1)) // 4
						{
							if (fileName.charAt(pointer) == '.') {
								return SUFFIX_JPEG;
							} // 5
						}
					}
				}
			} else if (c == 'e' || c == 'E') // 1
			{
				c = fileName.charAt(pointer--);


				if (c == 'p' || c == 'P') // 2
				{
					c = fileName.charAt(pointer--);


					if ((c == 'j' || c == 'J') && (pointer > -1)) // 3
					{
						if (fileName.charAt(pointer) == '.') {
							return SUFFIX_JPE;
						} // 4
					}
				}
			} else if (c == 'f' || c == 'F') // 1
			{
				c = fileName.charAt(pointer--);


				if (c == 'i' || c == 'I') // 2
				{
					c = fileName.charAt(pointer--);


					if (c == 'f' || c == 'F') // 3
					{
						c = fileName.charAt(pointer--);


						if ((c == 'j' || c == 'J') && (pointer > -1)) // 4
						{
							if (fileName.charAt(pointer) == '.') {
								return SUFFIX_JFIF;
							} // 5
						}
					} else if ((c == 't' || c == 'T') && (pointer > -1)) // 3
					{
						if (fileName.charAt(pointer) == '.') {
							return SUFFIX_TIF;
						} // 4
					}
				} else if (c == 'f' || c == 'F') // 2
				{
					c = fileName.charAt(pointer--);


					if (c == 'i' || c == 'I') // 3
					{
						c = fileName.charAt(pointer--);


						if ((c == 't' || c == 'T') && (pointer > -1)) // 4
						{
							if (fileName.charAt(pointer) == '.') {
								return SUFFIX_TIFF;
							} // 5
						}
					}
				}
			}
		}


		return null;
	}


	/***************************************************************************
	 * 
	 * 解析出图片中存储的照相时间
	 * 
	 * 
	 * 正常相片(Normal),时间格式如下:
	 * 
	 * 2001:01:02 12:23:56[NULL]2001:01:02 12:23:56
	 * 
	 * 一般都是400到800字节之间,极个别在200和1500左右
	 * 
	 * 还有些相机(如HP PhotoSmart R607)竟然在3100左右
	 * 
	 * 
	 * 特殊相片(Special),如富士系列相片FUJIFILM,时间格式如下:
	 * 
	 * 2006-12-24T13:55:42+08:00
	 * 
	 * 一般在8000以内任意地方,非常臃长
	 * 
	 * 
	 * 综上考虑,我不得不用10240来代替原来的2048
	 * 
	 * 或者我可以使用分段方法,将出现最多的段放在前面,最少的段放后面,我需要统计
	 * 
	 * 现在我遇到的最大的为16000,也就是从2500到16000都有,很少,所以忽略了
	 * 
	 * 现在已经分段了
	 * 
	 **************************************************************************/
	private final char[] getPictureDateTime(File file)
			throws FileNotFoundException, IOException {
		FileInputStream fis = new FileInputStream(file);


		// //////////////////////////////////////////////////////////////////////
		//
		// 时间信息全在文件前10240字节内,我们一次读入,一个一个字节分析,
		//
		// 但是当需要读入的内容大于10240字节时,最好分批读入,每次2048或1024
		//
		// //////////////////////////////////////////////////////////////////////
		byte[] buffer = new byte[2048];


		int readLength = 0;


		int remain = 0;


		int n = 128; // 为防止溢出,而且没必要搜索最初的128字节


		int readTimes = 8; // readTimes和buffer.length的乘积应当在10000至16000左右,保证只搜索图片前16000字节


		int foundTimes = 0; // 找到有效时间的次数,我们使用第二次找到的时间


		int foundOffset = 0; // 在哪找到的


		byte tailByte = 0; // 从当前位置向后偏移18,就是时间的最后一位,判断字符是否符合要求


		while (--readTimes >= 0
				&& (readLength = fis.read(buffer, remain, buffer.length
						- remain)
						+ remain) >= 0) {
			// //////////////////////////////////////////////////////////////////
			//
			// 为速度,不准备转换成char,直接比较数字,如下:
			//
			// NULL 0
			//
			// - 45
			//
			// 0 48
			// 1 49
			// 2 50
			// 3 51
			// 4 52
			// 5 53
			// 6 54
			// 7 55
			// 8 56
			// 9 57
			// / 47
			// : 58
			//
			// 空格 32
			//
			// T 84
			// t 116
			//
			// D 68
			// d 100
			//
			// O 79
			// o 111
			//
			// //////////////////////////////////////////////////////////////////


			while ((remain = readLength - n) > 0) {
				if (remain <= 38 && n >= 19) // 快要到末尾了,把剩余的字节复制到头部,我们重新开始
				{
					System.arraycopy(buffer, n -= 19, buffer, 0, remain += 19);


					foundOffset += n;
					n = 0;
					break;
				}


				tailByte = buffer[n + 18];


				// 末尾是数字
				if (tailByte > 47 && tailByte < 58) {
					// 必须是数字开头,并且时钟与分钟、分钟与秒钟之间是“:”
					if (buffer[n] > 47 && buffer[n] < 58
							&& buffer[n + 16] == 58 && buffer[n + 13] == 58) {
						// 日期与时间分隔的是空格“ ”,并且年与月、月与日之间是“:”,也就是2006:06:06 06:06:06
						if (buffer[n + 10] == 32 && buffer[n + 7] == 58
								&& buffer[n + 4] == 58) {
							foundTimes++;


							// Normal,两个时间在一起,或是第二次找到的时间
							if ((buffer[n + 36] == 58 && buffer[n + 33] == 58
									&& buffer[n + 30] == 32
									&& buffer[n + 27] == 58 && buffer[n + 24] == 58)
									|| (foundTimes == 2)) {
								foundOffset += n;


								// System.err.println( foundOffset );


								fis.close();
								return parseDateTime(buffer, n, 19);
							}
						}


						// 日期与时间分隔的是“T”或“t”,并且年与月、月与日之间是“-”,也就是2006-06-06T06:06:06
						else if ((buffer[n + 10] == 84 || buffer[n + 10] == 116)
								&& buffer[n + 7] == 45 && buffer[n + 4] == 45) {
							foundTimes++;


							// Special,含有“DateTimeOriginal”,只判断“D”或“d”、“T”或“t”、“O”或“o”三个字符
							if ((buffer[n - 9] == 79 || buffer[n - 9] == 111)
									&& (buffer[n - 13] == 84 || buffer[n - 13] == 116)
									&& (buffer[n - 17] == 68 || buffer[n - 17] == 100)) {
								foundOffset += n;


								// System.err.println( foundOffset );


								fis.close();
								return parseDateTime(buffer, n, 19);
							}
						}
					}


					// 别忘了移位
					n++;
				}


				// 末尾是“:”,向后移动2位
				else if (tailByte == 58) {
					// //////////////////////////////////////////////////////////
					//
					// [ CANON 42 H 2006:12:24 12:33:08 2006:12:24 12:33:08 ]
					// |
					// [
					// 2006-12-24T12:33:08+08:00]
					// |
					// 0000:00:00 00:00:0A
					// |
					// 0000-00-00T00:00:0A
					// |
					// 0000:00:00 00:00:0A
					// |
					// 0000-00-00T00:00:0A
					//
					// //////////////////////////////////////////////////////////
					n += 2;
				}


				// 末尾是空格“ ”、“T”、“t”,向后移动8位
				else if (tailByte == 32 || tailByte == 84 || tailByte == 116) {
					// //////////////////////////////////////////////////////////
					//
					// [ CANON 42 H 2006:12:24 12:33:08 2006:12:24 12:33:08 ]
					// |
					// [
					// 2006-12-24T12:33:08+08:00]
					// |
					// 0000:00:00 00:00:0A
					// |
					// 0000-00-00T00:00:0A
					// |
					// 0000:00:00 00:00:0A
					// |
					// 0000-00-00T00:00:0A
					//
					// //////////////////////////////////////////////////////////
					n += 8;
				}


				// 末尾是“-”,向后移动11位
				else if (tailByte == 45) {
					// //////////////////////////////////////////////////////////
					//
					// [
					// 2006-12-24T12:33:08+08:00]
					// |
					// 0000-00-00T00:00:0A
					// |
					// 0000-00-00T00:00:0A
					//
					// //////////////////////////////////////////////////////////
					n += 11;
				}


				// 末尾不包含以上任何字符,整块向后移动19位
				else {
					// //////////////////////////////////////////////////////////
					//
					// [ CANON 42 H 2 f light 24 F 55 ]
					// | |
					// 0000-00-00T00:00:0A |
					// |
					// 0000-00-00T00:00:0A
					//
					// //////////////////////////////////////////////////////////
					n += 19;
				}
			}
		}


		fis.close();
		return null;
	}


	/***************************************************************************
	 * 
	 * 将已经定位好的日期时间提取出来
	 * 
	 **************************************************************************/
	private final char[] parseDateTime(byte[] buf, int off, int len) {
		if (buf == null || off < 0 || len < 0 || off + 1 > buf.length
				|| off + len > buf.length) {
			return null;
		}


		char[] array = new char[len];


		byte b;




		for (int i = 0; i < len; i++) {
			b = buf[off + i];
			


			if (b >= 48/* 0 */&& b <= 57/* 9 */) {
				array[i] = (char) b;
			} // 数字,没有检查日期合法性


			else if (b == 58/* : */ && i <8) {
				array[i] = PRI_SEPARATOR;
			} // 由于“:”不能用于文件名,我们用“-”代替
			else if (b == 58/* : */ && i > 2) {
				array[i] = PRI_SUB_SEPARATOR;
			} 
			else {
				array[i] = SUB_SEPARATOR;
			} // NULL值或其他非数值用空格代替
			
		}
		System.out.println(array);
		return array;
	}


	/***************************************************************************
	 * 
	 * 检查新文件名称是否已被占用,如果没被占用,则修改名称
	 * 
	 **************************************************************************/
	private final String rename(File parent, File file, String name,
			char[] prefix, char[] suffix, int number) {
		if (parent == null || file == null || prefix == null || suffix == null) {
			return null;
		}


		char[] array = new char[64/**/];


		// //////////////////////////////////////////////////////////////////////


		int pointer = array.length - suffix.length;


		System.arraycopy(suffix, 0, array, pointer, suffix.length); // [ .jpg]


		if (number > 0/*-1*/) {
			pointer = writeNumberSequence(array, --pointer, number); // [
																		// 001.jpg]


			array[pointer] = SUB_SEPARATOR/**/; // [ _001.jpg]
		}


		int temp = pointer = pointer - prefix.length;


		System.arraycopy(prefix, 0, array, pointer, prefix.length); // [2008-01-01
																	// 01-01-01_001.jpg]


		// System.out.println( "Get new file name: " + new String( array,
		// pointer, array.length - pointer ) );


		// //////////////////////////////////////////////////////////////////////


		if (array.length - temp == name.length()) {
			for (int i = 0; temp < array.length; temp++, i++) {
				// 从pointer的点开始字符比较


				if (array[temp] != name.charAt(i)) {
					break;
				}
			}
		}


		if (temp == array.length) {
			return null/**/;
		} // 如果图片已经改好了,不需要再次修改


		// //////////////////////////////////////////////////////////////////////


		String newName = new String(array, pointer, array.length - pointer);


		File newFile = new File(parent, newName);


		if (newFile.exists()) {
			return rename(parent, file, name, prefix, suffix, number + 1);
		} // 已经存在同名但本质不同的图片


		else if (file.renameTo(newFile)) {
			return newName;
		} // 改名成功,测试发现renameTo很耗时间


		return null;
	}


	/***************************************************************************
	 * 
	 * 得到诸如001、002、012、569、999、0102、1345、4567、56789这样的数字序列
	 * 
	 **************************************************************************/
	private final int writeNumberSequence(char[] array, int offset, int number) {
		if (array == null || offset < 0 || number < 0) {
			return offset;
		}


		int i = 0, pointer = offset, temp = number;


		for (; i < sequenceLength; i++, temp /= 10) {
			array[pointer--] = (char) (temp % 10 + 48); // 48是'0'的ASCII码
		}


		for (; temp > 0; temp /= 10) {
			array[pointer--] = (char) (temp % 10 + 48); // 48是'0'的ASCII码
		}


		return pointer;
	}


	public final int getTotalFolders() {
		return totalFolders;
	}


	public final int getTotalFiles() {
		return totalFiles;
	}


	public final int getTotalPictures() {
		return totalPictures;
	}


	public final int getParsedPictures() {
		return parsedPictures;
	}


	public final int getRenamedPictures() {
		return renamedPictures;
	}


	/***************************************************************************
	 * 
	 * 既向控制台显示,又向日志写入
	 * 
	 **************************************************************************/
	private final static void logger(String message, boolean both) {
		if (message == null || message.length() < 1) {
			return;
		}


		if (both) {
			System.out.println(message);
		}


		System.err.println(message);
	}


	public static void main(String[] args) {
		try {
			System.setErr(new PrintStream(new FileOutputStream("log.txt")));


			long start = System.currentTimeMillis();


			PictureRenamer rpodt = new PictureRenamer(10240, 3);


			rpodt.listPictures(null, "img");


			logger("/r/n共有文件夹:" + (rpodt.getTotalFolders()) + "个", true);


			logger("/r/n共有文件:" + (rpodt.getTotalFiles()) + "个", true);


			logger("/r/n共有图片:" + (rpodt.getTotalPictures()) + "张", true);


			logger("/r/n有效图片:" + (rpodt.getParsedPictures()) + "张", true);


			logger("/r/n修改成功:" + (rpodt.getRenamedPictures()) + "张", true);


			logger("/r/n修改失败:"
					+ (rpodt.getParsedPictures() - rpodt.getRenamedPictures())
					+ "张", true);


			logger("/r/n总共耗时:" + (System.currentTimeMillis() - start) + "毫秒",
					true);
		} catch (FileNotFoundException fnfe) {
			fnfe.printStackTrace();
		}


		catch (IOException ioe) {
			ioe.printStackTrace();
		}


		catch (Exception e) {
			e.printStackTrace();
		}
	}
}

你可能感兴趣的:(java基础)