I have this kind of file structure
MALE:FooBar:32 FEMALE:BarFoo:23
Where I would want to identify the gender and age of person, <Gender>:<Name>:<age>
try{
BufferedReader in = new BufferedReader(new FileReader("people.ser"));
String s;
while((s = in.readLine()) != null){
String[] var = s.split(":");
//var[0]=MALE etc etc
addGender.add(var[0]);
}
}catch(Exception e){
e.printStackTrace();
}
- Is using a delimiter (like a
:
in this case) to split string considered a bad practice? - What about using the array from the splitted string to store it in some place?
- Are there any alternatives and better file structure?
-
\$\begingroup\$ String.split(RegEx) is the now recommended for new Java'versions (StringTokenizer for old version compatibility). With 'palacsint' advices, you code look fine. \$\endgroup\$cl-r– cl-r2012年08月27日 08:06:42 +00:00Commented Aug 27, 2012 at 8:06
2 Answers 2
I don't think that using :
is a bad practice but you have to escape it somehow if it occurs inside your data. Anyway, I'd consider using XML or JSON here.
Some notes about the code:
- You should close the stream (in a
finally
block). See Guideline 1-2: Release resources in all cases in Secure Coding Guidelines for the Java Programming Language - The
.ser
file extension is often used for serialized Java objects. I'd use something else to avoid the possible confusion. It's a good practice to set the character set when you read a text file. The used
FileReader
always uses the default charset which could vary from system to system. Consider usingInputStreamReader
andFileInputStream
as the documentation ofFileReader
says. Here is an example:FileInputStream fileInputStream = null; InputStreamReader inputStreamReader = null; BufferedReader bufferedReader = null; try { fileInputStream = new FileInputStream("people.dat"); inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8"); bufferedReader = new BufferedReader(inputStreamReader); // use BufferedReader here } finally { IOUtils.closeQuietly(bufferedReader); IOUtils.closeQuietly(inputStreamReader); IOUtils.closeQuietly(fileInputStream); }
It uses
IOUtils
from Apache Commons IO and closes theFileInputStream
even if the constructor ofInputStreamReader
orBufferedReader
throws an exception.
-
\$\begingroup\$ How would I do number 3? \$\endgroup\$KyelJmD– KyelJmD2012年08月26日 01:19:54 +00:00Commented Aug 26, 2012 at 1:19
-
\$\begingroup\$ @KyelJmD: See the edit, please. \$\endgroup\$palacsint– palacsint2012年08月26日 01:27:21 +00:00Commented Aug 26, 2012 at 1:27
-
\$\begingroup\$ why did you use final? \$\endgroup\$KyelJmD– KyelJmD2012年08月26日 05:39:10 +00:00Commented Aug 26, 2012 at 5:39
-
\$\begingroup\$ @KyelJmD:
final
helps readers and maintainers, because they know that the reference always points to the same instance and it doesn't change later. programmers.stackexchange.com/questions/115690/… but you can find other questions on Programmers.SE in the topic. \$\endgroup\$palacsint– palacsint2012年08月26日 08:46:38 +00:00Commented Aug 26, 2012 at 8:46 -
\$\begingroup\$ I would place those final variables in the class? or inside a method that calls them? \$\endgroup\$KyelJmD– KyelJmD2012年08月26日 09:50:24 +00:00Commented Aug 26, 2012 at 9:50
Scanner is a bit easier to use then BufferedReader...
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
try {
File f = new File("people.ser");
Scanner sc = new Scanner(f);
List<Person> people = new ArrayList<Person>();
while(sc.hasNextLine()){
String line = sc.nextLine();
String[] details = line.split(":");
String gender = details[0];
String name = details[1];
int age = Integer.parseInt(details[2]);
Person p = new Person(gender, name, age);
people.add(p);
}
for(Person p: people){
System.out.println(p.toString());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
class Person{
private String gender;
private String name;
private int age;
public Person(String gender, String name, int age){
this.gender = gender;
this.setName(name);
this.age = age;
}
/**
* @return the gender
*/
public String getGender() {
return gender;
}
/**
* @param gender the gender to set
*/
public void setGender(String gender) {
this.gender = gender;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}
public String toString(){
return this.gender + " " + this.name + " " + this.age;
}
}
-
\$\begingroup\$
toString()
method should useStringBuilder
instead of concatenation. \$\endgroup\$Eva– Eva2013年01月17日 00:39:18 +00:00Commented Jan 17, 2013 at 0:39 -
\$\begingroup\$ Since the toString() method is likely only used for debugging purposes, I'd say readability trumps performance here and the current implementation is a lot more readable. In case it is used in heavy iteration, that might be a different case. \$\endgroup\$Nihathrael– Nihathrael2014年11月25日 09:02:04 +00:00Commented Nov 25, 2014 at 9:02