文件操作小例
问题描述:
给定一个代码文件,设计程序计算出其中代码行数量,空行数量,注解数量,分号数量,逗号数量,关键字数量(这里我只考虑了for关键字)
问题思路:
直接使用bufferedReader读取计算出 代码行,空行,分号,逗号数量
那么对于注解(块注解,行注解),关键字怎么处理?—>使用正则表达式匹配
省略点
这里我就直接对文件操作了,不考虑文件夹读取,给个文件(支持文件夹读取)读取示例:
private final List<String> list = new ArrayList<>();
public List<String> getAllFiles(String path){
File file = new File(path);
if (file.isFile()){
list.add(file.toString());
return list;
}
File[] files = file.listFiles();
for (File file1 :files){
if (file1.isFile()){
list.add(file1.toString());
}
if (file1.isDirectory()){
getAllFiles(file1.toString());
}
}
return list;
}
设置常量类存放正则表达式和常量
额,正则表达式可能写的不太好,见谅
public class MatchCheck {
/**
* 块注释匹配开始及多余字符
* (什么是多余字符? 可能有的人的代码多了空格,字母,虽然不符合规范,但仍然可以)
*/
public final static String BLOCK_COMMENTS_START = "\\s*/\\*{2,}[\\u4e00-\\u9fa5\\w]*";
//快注释匹配结束 */ 及多余字符
public final static String BLOCK_COMMENTS_END = "\\s*[\\u4e00-\\u9fa5\\w]*\\*{1,}/";
//匹配 //符号
public final static String LINE_COMMENTS = "\\s*//[\\u4e00-\\u9fa5\\w]*";
/**
* 匹配 关键字 for及其变形
* 暂时只考虑了
* for for(int for(;i<5;)三种大致类型
*/
public final static String KEY_WORD_OF_FOR = "\\s*for\\({0,1}\\w*.*\\){0,1}";
public final static String KEYWORD_SEMICOLON = ";";
public final static String KEYWORD_COMMA = ",";
}
实现方法
目前想到两种方法:
-
每个函数中使用bufferedReader扫描
注意点:
bufferedReader扫描一次后,指针到文件底,需要重新将指针指到文件头,bufferedReader中提供了mark()和reset()解决
很明显,此方法需要花费大量时间用在读取文件上,不推荐这种做法。
-
初始化时扫描文件,使用List记录文件内容,以后函数中只对list操作
方法1代码:
public final class LineHelper extends MatchCheck{
private final File file;
private BufferedReader bufferedReader = null;
private int keyword_for; //for关键字的数量
private int keyword_semicolon; //分号关键字的数量
private int keyword_comma; //逗号的数量 Java中逗号用在传参和定义参数中,当然这里注释中也会有(中文逗号)
private boolean isCount = false; //判断是否运行过 计算关键字函数
public LineHelper(File file){
this.file = file;
try {
bufferedReader = new BufferedReader(new FileReader(file));
bufferedReader.mark((int)file.length()+1);
} catch (Exception e) {
System.out.println("文件不存在"+e.getMessage());
try {
throw e;
} catch (IOException ignored) {
}
}
}
public LineHelper(String path){
this(new File(path));
}
public int getKeyword_for(){
if (isCount)
return keyword_for;
count_Key();
isCount = true;
return keyword_for;
}
public int getKeyword_semicolon() {
if (isCount)
return keyword_semicolon;
count_Key();
isCount = true;
return keyword_semicolon;
}
public int getKeyword_comma(){
if (isCount)
return keyword_comma;
count_Key();
isCount = true;
return keyword_comma;
}
private void init(){
try {
bufferedReader.reset();
} catch (IOException e) {
e.printStackTrace();
}
}
//得到文件总行数
public int getFileAllLine(){
int number = 0;
try (Scanner input = new Scanner(this.file)) {
while (input.hasNextLine()){
input.nextLine();
number++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return number;
}
//得到文件代码行
public int getFileCodeLine(){
return getFileAllLine() - getFileCommentsLine() - getFileNullLine();
}
//得到文件空行
public int getFileNullLine(){
int number = 0;
try (Scanner input = new Scanner(this.file)) {
while (input.hasNextLine()){
String line = input.nextLine();
if (line.equals(""))
number++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return number;
}
//得到文件注释行
public int getFileCommentsLine(){
init();
int number = 0, linNumber = 0;
int sum = 0,front ,end;
try {
String StringValue;
while ((StringValue = bufferedReader.readLine())!= null){
number++;
if (isMatchOk(StringValue,LINE_COMMENTS))
linNumber++;
if (isMatchOk(StringValue,BLOCK_COMMENTS_START)){
front = number;
while ((StringValue = bufferedReader.readLine())!= null){
number++;
if (isMatchOk(StringValue,BLOCK_COMMENTS_END)){
end = number;
sum += end -front +1;
break;
}
}
}
}
}catch (Exception e){
e.printStackTrace();
}
return sum + linNumber;
}
//正则匹配是否成功
private boolean isMatchOk(String StringValue,String regex){
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(StringValue);
//System.out.println(StringValue);
return matcher.matches();
}
//计算关键字
private void count_Key(){
init();
try {
String StringValue;
while ((StringValue = bufferedReader.readLine())!= null){
String[] split = StringValue.split(" ");
for (String s : split) {
if (isMatchOk(s, KEY_WORD_OF_FOR)) {
keyword_for++;
}
}
keyword_semicolon += getSymbolNumber(StringValue,KEYWORD_SEMICOLON);
keyword_comma += getSymbolNumber(StringValue,KEYWORD_COMMA);
}
}catch (Exception e){
e.printStackTrace();
}
}
//对字符处理,计数
private int getSymbolNumber(String StringValue,String symbol){
String[] split = StringValue.split(symbol);
if(!StringValue.equals("") && StringValue.charAt(StringValue.length() -1) == symbol.charAt(0))
return split.length;
else
return split.length-1;
}
}
方法2代码:
public class LineStorageHelper extends MatchCheck{
private BufferedReader bufferedReader = null;
private int keyword_for; //for关键字的数量
private int keyword_semicolon; //分号关键字的数量
private int keyword_comma; //逗号的数量 Java中逗号用在传参和定义参数中,当然这里注释中也会有(中文逗号)
private boolean isCount = false; //判断是否运行过 计算关键字函数
private List<String> list;
public LineStorageHelper(File file){
try {
bufferedReader = new BufferedReader(new FileReader(file));
} catch (Exception e) {
System.out.println("文件不存在"+e.getMessage());
}
init();
}
public LineStorageHelper(String path){
this(new File(path));
}
//初始化
private void init(){
list = new ArrayList<>();
String StringValue;
try {
while ((StringValue = bufferedReader.readLine())!=null){
list.add(StringValue);
}
}catch (Exception e){
e.printStackTrace();
}
}
public int getKeyword_for(){
if (isCount)
return keyword_for;
count_Key();
isCount = true;
return keyword_for;
}
public int getKeyword_semicolon() {
if (isCount)
return keyword_semicolon;
count_Key();
isCount = true;
return keyword_semicolon;
}
public int getKeyword_comma(){
if (isCount)
return keyword_comma;
count_Key();
isCount = true;
return keyword_comma;
}
//得到文件总行数
public int getFileAllLine(){
return list.size();
}
//得到文件代码行
public int getFileCodeLine(){
return getFileAllLine() - getFileCommentsLine() - getFileNullLine();
}
//得到文件空行
public int getFileNullLine(){
int number = 0;
for (String s:list){
if (s.equals(""))
number++;
}
return number;
}
//得到文件注释行
public int getFileCommentsLine() {
int commentLine = 0;
for (int i = 0; i < list.size(); i++) {
if (isMatchOk(list.get(i), LINE_COMMENTS))
commentLine++;
if (isMatchOk(list.get(i), BLOCK_COMMENTS_START)) {
int count = 1;
i++;
for (; i < list.size(); i++) {
count++;
if (isMatchOk(list.get(i), BLOCK_COMMENTS_END))
break;
}
commentLine += count;
}
}
return commentLine;
}
//正则匹配是否成功
private boolean isMatchOk(String StringValue,String regex){
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(StringValue);
return matcher.matches();
}
//计算关键字
private void count_Key(){
for (String StringValue:list){
String[] split = StringValue.split(" ");
for (String s : split) {
if (isMatchOk(s, KEY_WORD_OF_FOR)) {
keyword_for++;
}
}
keyword_semicolon += getSymbolNumber(StringValue,KEYWORD_SEMICOLON);
keyword_comma += getSymbolNumber(StringValue,KEYWORD_COMMA);
}
}
//匹配符号 这里有;和 ,
private int getSymbolNumber(String StringValue,String symbol){
String[] split = StringValue.split(symbol);
if(!StringValue.equals("") && StringValue.charAt(StringValue.length() -1) == symbol.charAt(0))
return split.length;
else
return split.length-1;
}
}
测试:
读取150行的java文件
方法一平均用时 78ms
方法二平均用时38ms
很明显,方法一需要多次将数据从硬盘读取到内存,而方法二只需要一次