我已经将文件读入String。 该文件包含各种名称,每行一个名称。 现在的问题是我想在String数组中使用这些名称。
为此我写了以下代码:
String [] names = fileString.split("
"); // fileString is the string representation of the file
但是我没有得到所需的结果,并且在分割字符串后获得的数组长度为1.这意味着"fileString"没有" n"字符,但文件中有" n"字符。
那么如何解决这个问题呢?
为什么要保留 n。 你能不能假设它在那里?
那么使用Apache Commons(Commons IO和Commons Lang)呢?
String[] lines = StringUtils.split(FileUtils.readFileToString(new File("...")), '
');
+1 - 交换一行代码以依赖Apache Commons IO和Lang。
请注意,现在这是FileUtils.readFileToString
问题不在于你如何拆分字符串;那个位是正确的。
您必须查看如何将文件读取到字符串。你需要这样的东西:
private String readFileAsString(String filePath) throws IOException {
StringBuffer fileData = new StringBuffer();
BufferedReader reader = new BufferedReader(
new FileReader(filePath));
char[] buf = new char[1024];
int numRead=0;
while((numRead=reader.read(buf)) != -1){
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
}
reader.close();
return fileData.toString();
}
虽然正确我对任何看到这个的人都有一个警告:我不会使用这个确切的代码片段,因为如果抛出IOException,读者永远不会关闭并且可能导致挂起的文件读取器永远不会被垃圾收集在* nix中world意味着你最终会耗尽文件句柄,你的JVM就会崩溃。
另一个问题是FileReader隐含地接收了默认情况下的任何字符集。中间String也是不必要的。
StringBuilder可能是比StringBuffer更好的选择。从StringBuffer javadoc开始:"从发布JDK 5开始,这个类已经补充了一个设计用于单个线程StringBuilder的等效类。通常应优先使用StringBuilder类,因为它支持所有相同的操作但它更快,因为没有同步。"
根据Garrett Rowe和Stan James的建议,您可以使用java.util.Scanner:
try (Scanner s = new Scanner(file).useDelimiter("\\Z")) {
String contents = s.next();
}
要么
try (Scanner s = new Scanner(file).useDelimiter("\
")) {
while(s.hasNext()) {
String line = s.next();
}
}
此代码没有外部依赖项。
警告:您应该将charset编码指定为Scanner构造函数的第二个参数。在这个例子中,我使用的是平台的默认值,但这肯定是错误的。
以下是如何使用java.util.Scanner和正确的资源和错误处理的示例:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.Iterator;
class TestScanner {
public static void main(String[] args)
throws FileNotFoundException {
File file = new File(args[0]);
System.out.println(getFileContents(file));
processFileLines(file, new LineProcessor() {
@Override
public void process(int lineNumber, String lineContents) {
System.out.println(lineNumber +":" + lineContents);
}
});
}
static String getFileContents(File file)
throws FileNotFoundException {
try (Scanner s = new Scanner(file).useDelimiter("\\Z")) {
return s.next();
}
}
static void processFileLines(File file, LineProcessor lineProcessor)
throws FileNotFoundException {
try (Scanner s = new Scanner(file).useDelimiter("\
")) {
for (int lineNumber = 1; s.hasNext(); ++lineNumber) {
lineProcessor.process(lineNumber, s.next());
}
}
}
static interface LineProcessor {
void process(int lineNumber, String lineContents);
}
}
+1用于最简单的原生解决方案。顺便说一句,不要忘记使用scanner.close();防止资源泄漏
@mmdemirbas,好的我已经添加了一个包含资源和错误处理的完整示例。谢谢你的提醒。
当读取与预期编码不同的编码时,扫描程序有一个令人讨厌的错误,请参阅:stackoverflow.com/questions/8330695/
@golimar,错误在我自己的代码中:我应该将charset指定为Scanner构造函数的第二个参数,而不是依赖于默认的charset。
@MarcelloNuccio不,问题是当Scanner找到的编码与指定的编码不同(或默认编码)时,它会退出返回部分字符串(具有随机大小)并且不会给出任何错误或警告消息
@golimar同意:Scanner中的错误报告是错误的。但是使用错误的编码来读取文件是我自己的代码中的一个错误。如何在不知道字符编码的情况下阅读一些文字?
@MarcelloNuccio True。但是,有时您需要的文件的唯一部分是ascii-only(例如,带有ascii-only命令的shell脚本和将被丢弃的非ascii注释)
请参阅我对stackoverflow.com/a/52971742/453605的评论
特别是我喜欢这个使用此处描述的java.nio.file包。
String content = new String(Files.readAllBytes(Paths.get("/path/to/file")));
很酷啊!
这可能是最好的答案!!
您可以将文件读入List而不是String,然后转换为数组:
//Setup a BufferedReader here
List list = new ArrayList();
String line = reader.readLine();
while (line != null) {
list.add(line);
line = reader.readLine();
}
String[] arr = list.toArray(new String[0]);
或者甚至把它留作阵列。
或者可以完全保留文件
Java中没有可以读取整个文件的内置方法。所以你有以下选择:
使用非标准的库方法,例如Apache Commons,请参阅romaintaz的答案中的代码示例。
循环一些read方法(例如FileInputStream.read,读取字节,或FileReader.read,读取字符;两者都读取到预分配的数组)。这两个类都使用系统调用,因此如果您一次只读取少量数据(例如,小于4096字节),则必须通过缓冲(BufferedInputStream或BufferedReader)来加速它们。
环绕BufferedReader.readLine。存在一个基本问题,它丢弃信息是否在文件的末尾有'
' - 例如,它无法区分空文件和仅包含换行符的文件。
我用这个代码:
// charsetName can be null to use the default charset.
public static String readFileAsString(String fileName, String charsetName)
throws java.io.IOException {
java.io.InputStream is = new java.io.FileInputStream(fileName);
try {
final int bufsize = 4096;
int available = is.available();
byte[] data = new byte[available < bufsize ? bufsize : available];
int used = 0;
while (true) {
if (data.length - used < bufsize) {
byte[] newData = new byte[data.length << 1];
System.arraycopy(data, 0, newData, 0, used);
data = newData;
}
int got = is.read(data, used, data.length - used);
if (got <= 0) break;
used += got;
}
return charsetName != null ? new String(data, 0, used, charsetName)
: new String(data, 0, used);
} finally {
is.close();
}
}
上面的代码具有以下优点:
这是正确的:它读取整个文件,而不是丢弃任何字节。
它允许您指定文件使用的字符集(编码)。
它很快(无论文件包含多少个换行符)。
它不会浪费内存(无论文件包含多少个换行符)。
FileReader fr=new FileReader(filename);
BufferedReader br=new BufferedReader(fr);
String strline;
String arr[]=new String[10];//10 is the no. of strings
while((strline=br.readLine())!=null)
{
arr[i++]=strline;
}
逐行读取文本文件并将结果放入字符串数组而不使用第三方库的最简单的解决方案是:
ArrayList names = new ArrayList();
Scanner scanner = new Scanner(new File("names.txt"));
while(scanner.hasNextLine()) {
names.add(scanner.nextLine());
}
scanner.close();
String[] namesArr = (String[]) names.toArray();
我一直用这种方式:
String content ="";
String line;
BufferedReader reader = new BufferedReader(new FileReader(...));
while ((line = reader.readLine()) != null)
{
content +="
" + line;
}
// Cut of the first newline;
content = content.substring(1);
// Close the reader
reader.close();
仅供参考:你经常阅读带有该代码的小文件吗?我本来期望在所有String连接中出现重大的性能损失......我不是故意要消极,我只是好奇。
嗯,是的......这种方法是否被弃用了?哦,FYI是什么意思?
FYI = For Your Information,是Web上使用的众多常见缩写词之一。
为什么要收集字符串而不是每行一个字符串列表?您通常需要事后对收集的数据执行某些操作。
我想Adam指出的问题是你在循环中进行字符串连接+ =,这意味着你每次都创建一个新的String对象(因为字符串是不可变的)。这对性能产生了相当大的负面影响。使用StringBuilder(并执行append())而不是内容的字符串。
谢谢你的提示。我将在未来中使用这种方式。现在终于我得到了一个关于+ = operater和新实例的anwser。谢谢
你可以试试Cactoos:
import org.cactoos.io.TextOf;
import java.io.File;
new TextOf(new File("a.txt")).asString().split("
")
您还可以使用java.nio.file.Files将整个文件读入字符串列表,然后将其转换为数组等。假设一个名为filePath的String变量,以下两行将执行此操作:
List strList = Files.readAllLines(Paths.get(filePath), Charset.defaultCharset());
String[] strarray = strList.toArray(new String[0]);
如果只有InputStream,则可以使用InputStreamReader。
SmbFileInputStream in = new SmbFileInputStream("smb://host/dir/file.ext");
InputStreamReader r=new InputStreamReader(in);
char buf[] = new char[5000];
int count=r.read(buf);
String s=String.valueOf(buf, 0, count);
如果需要,您可以添加cycle和StringBuffer。
更简单(没有循环)但不太正确的方法是将所有内容读取到字节数组:
FileInputStream is = new FileInputStream(file);
byte[] b = new byte[(int) file.length()];
is.read(b, 0, (int) file.length());
String contents = new String(b);
另请注意,这有严重的性能问题。