使用扫描仪读取CSV()
我的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; 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(); } } }
所以这里是控制台的结果:
第一,最后,电子邮件,地址 1,地址 2 约翰·史密斯,胡说@ blah.com,123 圣 街, 简·史密斯,BLECH @ blech.com,4455 罗杰 CIR,容易 2
我是否正确使用扫描仪?
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,cd,e 1,2,3 4,5 X,Y,ZA,B
输出是:
a|b|cd|e 1|2|3 4|5 X|Y|ZA|B|
请停止编写错误的CSVparsing器!
我已经看到了数以百计的CSVparsing器和所谓的在线教程 。
几乎每个人都错了!
这不会是一件坏事,因为它不会影响我,但是试图编写CSV 阅读器并且出错的人也倾向于编写CSV 编写器 。 并让他们错了。 而这些我必须写parsing器。
请记住CSV(按照增加的顺序不那么明显):
- 可以引用值附近的字符
- 可以有其他的引用字符而不是“
- 甚至可以有其他引用字符比“和”
- 根本没有引号
- 甚至可以在某些值上引用字符而在其他值上不引用字符
- 可以有其他的分隔符,而且;
- 分隔符和(引用)值之间可以有空格
- 可以有其他的字符比ASCII
- 在每一行中应该具有相同数量的值,但并不总是如此
- 可以包含空的字段,或者引用:
"foo","","bar"
或不是:"foo",,"bar"
- 可以在值中包含换行符
- 如果它们没有分隔,则不能在值中包含换行符
- 值之间不能包含换行符
- 如果正确转义,可以在该值内具有分隔符
- 不使用反斜线来逃避分隔符,但…
- 使用引用字符本身来逃避它,例如
Frodo's Ring
将是'Frodo''s Ring'
- 可以在值的开始或结束处具有引号字符,或者甚至只有字符(
"foo""", """bar", """"
) - 甚至可以在没有引用的价值内具有引用的字符; 这一个没有逃脱
如果你认为这显然不是问题,那么再想一想。 我看到这些项目中的每一个都错误地实施了。 即使在主要的软件包。 (如办公室套件,客户关系pipe理系统)
有好的和正确的工作,现成的CSV阅读器和作家在那里:
- opencsv
- Ostermiller Java公用事业
如果你坚持写自己的,至less读CSV (非常短)的RFC 。
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); } }
如前所述,build议使用CSV库。 首先,这个(和useDelimiter(",")
解决scheme)将不能正确处理包含字符的带引号的标识符。
如果您绝对必须使用扫描仪,则必须通过其useDelimiter(...)
方法设置其分隔符。 否则它将默认使用全部空格作为分隔符。 尽pipe如前所述,使用CSV库是一件好事,因为这是他们最擅长的。
例如,这个分隔符将会在包含或不包含空格的逗号分割:
scanner.useDelimiter("\\s*,\\s*");
请查看java.util.Scanner API了解更多信息。
package take; public class DateUtil { // List of all date formats that we want to parse. // Add your own format here. private static List<SimpleDateFormat> dateFormats = new ArrayList<SimpleDateFormat>() { private static final long serialVersionUID = 1L; { add(new SimpleDateFormat("M/dd/yyyy")); add(new SimpleDateFormat("dd.M.yyyy")); add(new SimpleDateFormat("M/dd/yyyy hh:mm:ss a")); add(new SimpleDateFormat("dd.M.yyyy hh:mm:ss a")); add(new SimpleDateFormat("dd.MMM.yyyy")); add(new SimpleDateFormat("dd-MMM-yyyy")); } }; /** * Convert String with various formats into java.util.Date * * @param input * Date as a string * @return java.util.Date object if input string is parsed * successfully else returns null */ public static Date convertToDate(String input) { Date date = null; if(null == input) { return null; } for (SimpleDateFormat format : dateFormats) { try { format.setLenient(false); date = format.parse(input); } catch (ParseException e) { //Shhh.. try other formats } if (date != null) { break; } } return date; } }
那么,我在NetBeans 8.1中编写代码:
首先:创build一个新项目,selectJava应用程序并命名您的项目。
然后在public class之后修改你的代码,如下所示:
/** * @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()+"|"); }} } }