Java 使用Scanner()读取CSV
我的csv被读入System.out,但我注意到任何带有空格的文本都会被移到下一行(作为返回\n) 以下是我的csv的启动方式:Java 使用Scanner()读取CSV,java,csv,java.util.scanner,Java,Csv,Java.util.scanner,我的csv被读入System.out,但我注意到任何带有空格的文本都会被移到下一行(作为返回\n) 以下是我的csv的启动方式: first,last,email,address 1, address 2 john,smith,blah@blah.com,123 St. Street, Jane,Smith,blech@blech.com,4455 Roger Cir,apt 2 运行我的应用程序后,任何带有空格(地址1)的单元格都会被抛出到下一行 import java.io.File; i
first,last,email,address 1, address 2
john,smith,blah@blah.com,123 St. Street,
Jane,Smith,blech@blech.com,4455 Roger Cir,apt 2
运行我的应用程序后,任何带有空格(地址1)的单元格都会被抛出到下一行
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class main {
public static void main(String[] args) {
// -define .csv file in app
String fileNameDefined = "uploadedcsv/employees.csv";
// -File class needed to turn stringName to actual file
File file = new File(fileNameDefined);
try{
// -read from filePooped with Scanner class
Scanner inputStream = new Scanner(file);
// hashNext() loops line-by-line
while(inputStream.hasNext()){
//read single line, put in string
String data = inputStream.next();
System.out.println(data + "***");
}
// after loop, close scanner
inputStream.close();
}catch (FileNotFoundException e){
e.printStackTrace();
}
}
}
下面是控制台中的结果:
first,last,email,address
1,address
2
john,smith,blah@blah.com,123
St.
Street,
Jane,Smith,blech@blech.com,4455
Roger
Cir,apt
2
第一个,最后一个,电子邮件,地址
1、地址
2.
约翰,史密斯,blah@blah.com,123
圣。
街道,
简,史密斯,blech@blech.com,4455
罗杰
Cir,apt
2.
我是否错误地使用了扫描仪?如果您必须使用扫描仪,则必须通过其
useDelimiter(…)
方法设置其分隔符。否则,它将默认使用所有空白作为分隔符。更好的方法是使用CSV库,因为这是他们最擅长的
例如,此分隔符将在逗号上拆分(带或不带空格):
scanner.useDelimiter("\\s*,\\s*");
请查看更多关于此的信息
scanner.useDelimiter(",");
这应该行得通
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class TestScanner {
public static void main(String[] args) throws FileNotFoundException {
Scanner scanner = new Scanner(new File("/Users/pankaj/abc.csv"));
scanner.useDelimiter(",");
while(scanner.hasNext()){
System.out.print(scanner.next()+"|");
}
scanner.close();
}
}
对于CSV文件:
a,b,c d,e
1,2,3 4,5
X,Y,Z A,B
输出为:
a|b|c d|e
1|2|3 4|5
X|Y|Z A|B|
Scanner.next()
不读取换行符,而是读取由空格分隔的下一个标记(默认情况下,如果未使用useDelimiter()
更改分隔符模式)。要读取行,请使用Scanner.nextLine()
读取一行后,可以使用String.split(“,”
将该行分隔为多个字段。这样可以识别不包含所需字段数的行。使用useDelimiter(“,”)代码>将忽略文件的基于行的结构(每行由一列字段组成,字段之间用逗号分隔)。例如:
while (inputStream.hasNextLine())
{
String line = inputStream.nextLine();
String[] fields = line.split(",");
if (fields.length >= 4) // At least one address specified.
{
for (String field: fields) System.out.print(field + "|");
System.out.println();
}
else
{
System.err.println("Invalid record: " + line);
}
}
如前所述,建议使用CSV库。首先,此(和使用分隔符(“,”
解决方案)将无法正确处理包含,
字符的引用标识符。请停止编写错误的CSV解析器强>
我在网上看到了数百个CSV解析器和所谓的教程
几乎每个人都错了
这并不是一件坏事,因为它不会影响我,但那些试图编写CSV阅读器并出错的人也倾向于编写CSV阅读器。也会把他们弄错。这些我必须为之编写解析器
请记住CSV(按不明显程度增加的顺序):
值周围可以有引号字符
可以有除“”以外的其他引用字符
甚至可以有除“and”以外的其他引用字符
不能有任何引用字符
甚至可以在某些值上有引号字符,而在其他值上没有引号字符
可以有除、和以外的其他分离器李>
分隔符和(引用的)值之间可以有空格
可以有ascii以外的其他字符集
应在每行中具有相同数量的值,但并不总是如此
可以包含空字段,可以是带引号的:“foo”、“”、“bar”
,也可以不是:“foo”、“bar”
可以在值中包含换行符
如果值中没有分隔符,则不能包含新行
值之间不能包含换行符
如果正确转义,则可以在值内包含分隔符
不使用反斜杠转义分隔符,但
使用引用字符本身对其进行转义,例如,Frodo's Ring
将是“Frodo's Ring”
可以在值的开头或结尾使用引号字符,甚至可以作为唯一字符(“foo”“,“bar”“,”“
)
甚至可以在not quoted值中包含带引号的字符;这一个没有逃脱
如果你认为这显然不是问题,那么再想想。我看到这些项目中的每一项都执行错误。甚至在主要的软件包中。(如办公套房、CRM系统)
有好的和正确的开箱即用CSV阅读器和写入器:
如果您坚持自己编写代码,至少要阅读(非常简短)。好吧,我在NetBeans 8.1中编写代码:
首先:创建一个新项目,选择Java应用程序并命名您的项目
然后在public类之后修改代码,如下所示:
/**
* @param args the command line arguments
* @throws java.io.FileNotFoundException
*/
public static void main(String[] args) throws FileNotFoundException {
try (Scanner scanner = new Scanner(new File("C:\\Users\\YourName\\Folder\\file.csv"))) {
scanner.useDelimiter(",");
while(scanner.hasNext()){
System.out.print(scanner.next()+"|");
}}
}
}
按此分隔符拆分下一行():
(?=([^\“]*\”[^\“]*\”*[^\“]*$)”
我同意Scheintod的观点,即使用现有的CSV库从一开始就符合RFC-4180标准是一个好主意。除了提到的OpenCSV和Oster Miller之外,还有一系列其他CSV库。如果您对性能感兴趣,您可以查看。它表明
始终是使用JDK 6、7、8或9最快的。这项研究没有发现这三者中的任何一个存在任何RFC 4180兼容性问题OpenCSV和Oster Miller的速度都是它们的两倍。
我与作者没有任何关联,但关于uniVocity CSV解析器,由于其作者与该解析器的作者相同,该研究可能存在偏见
需要注意的是,《SimpleFlatMapper》的作者也发表了一篇仅比较这三者的文章。我看到了许多由于代码不处理引号(“)、引号中的换行符和引号中的引号而导致的生产问题;例如:“他说”“这个”“应该被解析为:他说了”“这个”
正如前面提到的,许多CSV解析示例只是读取一行,然后用分隔符分隔该行。这是相当不完整和有问题的
对于我和那些可能更喜欢build verses购买(或使用其他人的代码并处理他们的依赖关系)的人来说,我开始使用经典的文本解析编程,这对我很有用:
/**
* Parse CSV data into an array of String arrays. It handles double quoted values.
* @param is input stream
* @param separator
* @param trimValues
* @param skipEmptyLines
* @return an array of String arrays
* @throws IOException
*/
public static String[][] parseCsvData(InputStream is, char separator, boolean trimValues, boolean skipEmptyLines)
throws IOException
{
ArrayList<String[]> data = new ArrayList<String[]>();
ArrayList<String> row = new ArrayList<String>();
StringBuffer value = new StringBuffer();
int ch = -1;
int prevCh = -1;
boolean inQuotedValue = false;
boolean quoteAtStart = false;
boolean rowIsEmpty = true;
boolean isEOF = false;
while (true)
{
prevCh = ch;
ch = (isEOF) ? -1 : is.read();
// Handle carriage return line feed
if (prevCh == '\r' && ch == '\n')
{
continue;
}
if (inQuotedValue)
{
if (ch == -1)
{
inQuotedValue = false;
isEOF = true;
}
else
{
value.append((char)ch);
if (ch == '"')
{
inQuotedValue = false;
}
}
}
else if (ch == separator || ch == '\r' || ch == '\n' || ch == -1)
{
// Add the value to the row
String s = value.toString();
if (quoteAtStart && s.endsWith("\""))
{
s = s.substring(1, s.length() - 1);
}
if (trimValues)
{
s = s.trim();
}
rowIsEmpty = (s.length() > 0) ? false : rowIsEmpty;
row.add(s);
value.setLength(0);
if (ch == '\r' || ch == '\n' || ch == -1)
{
// Add the row to the result
if (!skipEmptyLines || !rowIsEmpty)
{
data.add(row.toArray(new String[0]));
}
row.clear();
rowIsEmpty = true;
if (ch == -1)
{
break;
}
}
}
else if (prevCh == '"')
{
inQuotedValue = true;
}
else
{
if (ch == '"')
{
inQuotedValue = true;
quoteAtStart = (value.length() == 0) ? true : false;
}
value.append((char)ch);
}
}
return data.toArray(new String[0][]);
}
使用合适的CSV库扫描程序默认分隔符是空白,这可能就是问题所在。我是否正确地认为它没有分隔换行符?即,它将“e\n1”和“5\nX”作为单个标记读取?可能更复杂
String[][] data = parseCsvData(new ByteArrayInputStream("foo,\"\",,\"bar\",\"\"\"music\"\"\",\"carriage\r\nreturn\",\"new\nline\"\r\nnext,line".getBytes()), ',', true, true);
for (int rowIdx = 0; rowIdx < data.length; rowIdx++)
{
System.out.println(Arrays.asList(data[rowIdx]));
}
[foo, , , bar, "music", carriage
return, new
line]
[next, line]