Não; pense em um campo string que tenha vírgulas dentro. Por exemplo:
2.34, "R. dos Bobos, 0", 2008-09-23
Você pode ver que há uma vírgula dentro de um campo, a qual não deve ser usada para separar os campos. Split não leva isso em conta, e expressões regulares têm certa dificuldade de tratar tais casos.
Se o campo string contiver aspas dentro, então elas devem ser duplicadas. O segundo campo contém a string Frederico “Fred” Abranches. Em um arquivo CSV ela apareceria como:
2.34, "Frederico ""Fred"" Abranches", 2008-09-23
Outra coisa mais chata que aparece em arquivos CSV é que o Excel em português gera arquivos CSV separados por “;” e com os números de ponto flutuante usando vírgulas flutuantes. Algo como:
2,34 ; "América; Ásia; Oceania" ; 2009-12-10
Embora haja soluções para tratamento de arquivos CSV, se você simplesmente não quiser usar nada fora da biblioteca-padrão do Java, pode tentar usar a java.io.StreamTokenizer.
StringTokenizer não cuida direito do caso em que há campos vazios, como em:
20,,3,56,"abcd",,dd
Nesse caso, StringTokenizer acaba “pulando” esse campo vazio. Se quiser usar alguma coisa que não pule campos vazios, e supor que em suas strings nunca vai aparecer uma vírgula (o que normalmente você não pode supor), use String.split com 2 parâmetros ( para o segundo, passe -1 ).
Eu falei tão bem do StreamTokenizer, mas ele tem alguns problemas com strings que contém aspas dentro (não tem com vírgulas dentro). Rode o programa abaixo, e veja o que estou falando.
import java.io.*;
import java.util.*;
class Cliente {
private double valor1, valor2;
private String endereco, nome;
public Cliente() {}
public Cliente (final double valor1_, final double valor2_, final String endereco_, final String nome_) {
valor1 = valor1_; valor2 = valor2_; endereco = endereco_; nome = nome_;
}
public void setValor1(final double valor1_) { valor1 = valor1_; }
public void setValor2(final double valor2_) { valor2 = valor2_; }
public void setEndereco(final String endereco_) { endereco = endereco_; }
public void setNome(final String nome_) { nome = nome_; }
public String toString() { return String.format ("[%.2f;%.2f;%s;%s]", valor1, valor2, endereco, nome); }
}
class TesteCSV {
private static String quote (final String str) {
StringBuilder sb = new StringBuilder();
sb.append ("\"");
for (int i = 0; i < str.length(); ++i) {
final char ch = str.charAt (i);
if (ch == '\"') {
sb.append ("\"");
}
sb.append (ch);
}
sb.append ("\"");
return sb.toString();
}
public void gerarArquivo() {
PrintWriter pw = null;
try {
pw = new PrintWriter(new BufferedWriter(new FileWriter ("teste.csv")));
// Note que printf ("%.2f") imprime com vírgulas, não com pontos, o que é indesejável neste caso.
// Portanto, iremos pôr um parâmetro adicional (Locale.US) para que ele imprima com pontos
pw.printf ("valor1,valor2,rua,nome%n");
pw.printf (Locale.US, "%.2f,%.2f,%s,%s%n", 2.34, 1002.45, quote ("R. dos Bobos, 0"), quote ("Frederico \"Fred\" Abranches"));
pw.printf (Locale.US, "%.2f,%.2f,%s,%s%n", 105.35, -2334.47, quote ("R. da Amargura, 13"), quote ("James Ryan Gosling O'Malley"));
} catch (IOException ex) {
ex.printStackTrace();
} finally {
pw.close();
}
}
public void lerArquivo() {
BufferedReader br = null;
try {
br = new BufferedReader (new FileReader ("teste.csv"));
List<Cliente> clientes = new ArrayList<Cliente>();
// A primeira linha contém apenas nomes
br.readLine();
for (String str = br.readLine(); str != null; str = br.readLine())
{
StringReader sr = new StringReader (str);
StreamTokenizer st = new StreamTokenizer (sr);
st.parseNumbers(); // necessário
Cliente cli = new Cliente();
int tokenType;
tokenType = st.nextToken();
if (tokenType == StreamTokenizer.TT_NUMBER)
cli.setValor1 (st.nval);
tokenType = st.nextToken(); // deve ser uma vírgula
tokenType = st.nextToken();
if (tokenType == StreamTokenizer.TT_NUMBER)
cli.setValor2 (st.nval);
tokenType = st.nextToken(); // deve ser uma vírgula
tokenType = st.nextToken();
if (tokenType == '\"' || tokenType == StreamTokenizer.TT_WORD)
cli.setEndereco (st.sval);
tokenType = st.nextToken(); // deve ser uma vírgula
tokenType = st.nextToken();
if (tokenType == '\"' || tokenType == StreamTokenizer.TT_WORD)
cli.setNome (st.sval);
clientes.add (cli);
}
System.out.println (clientes);
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (br != null) try { br.close(); } catch (IOException ex) {}
}
}
public static void main(String[] args) {
TesteCSV tc = new TesteCSV();
tc.gerarArquivo();
tc.lerArquivo();
}
}