So I have a text document called stock.txt which contains the following:
AAPL; Apple Inc.
IBM; International Business Machines Corp.
KO; The Coca-Cola Company
FB; Facebook Inc.
SBUX; Starbucks Corp.
And I want to store each element into a HashMap with the stock code as a key and the name of the company as the item. I originally tried storing all of it in an ArrayList however when I wanted to print out one line, for example:
AAPL;Apple Inc.
I would do:
System.out.println(array.get(0));
and it would give me the output:
APPL;Apple
and printing array.get(1) would give me the "Inc." part.
So my overarching question is how to I make sure that I can store these things properly in a HashMap so that I can get the whole string "Apple Inc." into one part of the Map.
Thanks!
You can try following:
InputStream stream=new FileInputStream(new File("path"));
BufferedReader reader=new BufferedReader(new InputStreamReader(stream));
String line;
String tok[];
Map<String, Object> map=new HashMap<String, Object>();
while((line=reader.readLine())!=null){
tok=line.split(";");
map.put(tok[0].trim(), tok[1].trim());
}
System.out.println(map);
Above code reads a file from a specific path and splits the read line from ; character and stores it into map.
Hope it helps.
There is no reason why you couldn't store the information into an ArrayList. The missing data has more to do with how you are reading and processing the file than the structure in which you are storing it. Having said that, using a HashMap will allow you to store the two parts of the line separately while maintaining the link between them. The ArrayList approach does not preserve that link - it is simply an ordered list.
Here's what I would do, which is similar to Darshan's approach (you will need Java 1.7+):
public HashMap<String, String> readStockFile(Path filePath, Charset charset)
{
HashMap<String, String> map = new HashMap<>();
try (BufferedReader fileReader =
Files.newBufferedReader(filePath, charset))
{
final int STOCK_CODE_GROUP = 1;
final int STOCK_NAME_GROUP = 2;
/*
* Regular expression - everything up to ';' goes in stock code group,
* everything after in stock name group, ignoring any whitespace after ';'.
*/
final Pattern STOCK_PATTERN = Pattern.compile("^([^;]+);\s*(.+)$");
String nextLine = null;
Matcher stockMatcher = null;
while ((nextLine = reader.readLine()) != null)
{
stockMatcher = STOCK_PATTERN.matcher(nextLine.trim());
if (stockMatcher.find(0))
if (!map.containsKey(stockMatcher.group(STOCK_CODE_GROUP)))
map.put(stockMatcher.group(STOCK_CODE_GROUP),
stockMatcher.group(STOCK_NAME_GROUP));
}
}
catch (IOException ioEx)
{
ioEx.printStackTrace(System.err); // Do something useful.
}
return map;
}
If you wish to retain insertion order into the map, substitute HashMap for a LinkedHashMap. The regular expression stuff (Pattern and Matcher) belongs to the java.util.regex package, while Path and Charset are in java.nio.file and java.nio.charset respectively. You'll need to use Path.getRoot(), Path.resolve(String filePath) and Charset.forName(String charset) to set up your arguments properly.
You may also want to consider what to do if you encounter a line that is not properly formatted or if a stock appears in the file twice. These will form 'else' clauses to the two 'ifs'.
Related
I am reading two different csv files and populating data into two different objects. I am splitting each line of csv file based on regex(regex is different for two csv files) and populating the object using each data of that array which is obtained by splitting each line using regex as shown below:
public static <T> List<T> readCsv(String filePath, String type) {
List<T> list = new ArrayList<T>();
try {
File file = new File(filePath);
FileInputStream fileInputStream = new FileInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)
list = bufferedReader.lines().skip(1).map(line -> {
T obj = null;
String[] data = null;
if (type.equalsIgnoreCase("Student")) {
data = line.split(",");
ABC abc = new ABC();
abc.setName(data[0]);
abc.setRollNo(data[1]);
abc.setMobileNo(data[2]);
obj = (T)abc;
} else if (type.equalsIgnoreCase("Employee")) {
data = line.split("\\|");
XYZ xyz = new XYZ();s
xyz.setName(Integer.parseInt(data[0]));
xyz.setCity(data[1]);
xyz.setEmployer(data[2]);
xyz.setDesignation(data[3]);
obj = (T)xyz;
}
return obj;
}).collect(Collectors.toList());} catch(Exception e) {
}}
csv files are as below:
i. csv file to populate ABC object:
Name,rollNo,mobileNo
Test1,1000,8888888888
Test2,1001,9999999990
ii. csv file to populate XYZ object
Name|City|Employer|Designation
Test1|City1|Emp1|SSE
Test2|City2|Emp2|
The issue is there can be a missing data for any of the above columns in the csv file as shown in the second csv file. In that case, I will get ArrayIndexOutOfBounds exception.
Can anyone let me know what is the best way to populate the object using the data of the string array?
Thanks in advance.
In addition to the other mistakes you made and that were pointed out to you in the comments your actual problem is caused by line.split("\\|") calling line.split("\\|", 0) which discards the trailing empty String. You need to call it with line.split("\\|", -1) instead and it will work.
The problem appears to be that one or more of the last values on any given CSV line may be empty. In that case, you run into the fact that String.split(String) suppresses trailing empty strings.
Supposing that you can rely on all the fields in fact being present, even if empty, you can simply use the two-arg form of split():
data = line.split(",", -1);
You can find details in that method's API docs.
If you cannot be confident that the fields will be present at all, then you can force them to be by adding delimiters to the end of the input string:
data = (line + ",,").split(",", -1);
Since you only use the first values few values, any extra trailing values introduced by the extra delimiters would be ignored.
I'm having a very unusual problem.
Basically, I'm trying to get the value associated with a key from a Map of Strings to Strings.
I know that the key I'm using is present; I'm using the same string I used to put it in!
I've print statements all over my code, and this is case I have...
Here is my dictionary characterDictionary
{thusChar=∴, spaceChar= , plusChar=+, equalsIndent=#, multiplyChar=×, equalsChar==, newlineChar=\n, divideChar=÷, subjectChar=:, variableIndent=#}
The very last key "variableIndent" is the trouble!
Here's the code...
System.out.println ( characterDictionary.get("variableIndent") );
which inappropriately outputs: null
I have checked, double checked and triple checked my code.
There is absolutely no difference between the key "variableIndent" and the string argument of characterDictionary.get("variableIndent"), yet it's behaving as if this key was not present.
I can absolutely guarantee this key is present, and that the two strings are identical.
All the other elements (the ones I've checked; about 3 so far) of the dictionary are retrieved as normal. Why is "variableIndent" with it's "#" value playing up?
You might notice the dictionary contains non ASCII characters, like "thusChar". Could this be related?
Thanks
(This seems like a very simple and trivial problem, as if I've made some pitifully silly mistake, but yet I just can't solve it!)
EDIT:
Okay, this HAS to be something about encoding.
I took the string key from the dictionary and compared it to my get argument.
When printed, they are identical, but java says they are not equal.
The key string came from a UTF-8 encoded text file, whilst the argument string came from a java Eclipse literal.
The characters are identical however.
What is the issue, and how can I resolve it?
Thanks!
EDIT:
Hmmm, here's what's actually happening behind the scenes.
I have a UTF-8 text file which contains the following content...
variableIndent,#
equalsIndent,#
spaceChar,
newlineChar,\n
multiplyChar,×
divideChar,÷
plusChar,+
equalsChar,=
subjectChar,:
thusChar,∴
I 'load' this file by reading in each line of the file as an ArrayList<String> element, by passing the directory of the file:
private static ArrayList<String> readLinesFile(String ResourceFile) {
ArrayList<String> Lines = new ArrayList<String>();
try{
InputStream fstream = FileManager.class.getResourceAsStream(ResourceFile);
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
while ((strLine = br.readLine()) != null) {
Lines.add(strLine); }
in.close(); }
catch (Exception e) {
System.out.println("Error: " + e.getMessage()); }
return Lines; }
Everything is fine up to here.
I then pass this ArrayList into a function that splits up each element by the "," character (using a function from a personal package; It is definitely not the issue), and adds the first part as a key to the second in the new dictionary.
private static Map<String, String> generateBaseUnits_Characters_Prefixes(ArrayList<String> FileContent) {
Map<String, String> BaseUnitsCache = new HashMap<String, String>();
ArrayList<String> currentLine;
for (int i=0; i<FileContent.size(); i++) {
currentLine = MiscellaneousFunctions.splitString(FileContent.get(i), ",");
BaseUnitsCache.put(currentLine.get(0), currentLine.get(1)); }
return BaseUnitsCache; }
and this produces the dictionary that is causing all the trouble.
I have a set of Key Literals that correspond to the character names in the text files, which I use to access the dictionary in the program.
public static String variableIndentKey = "variableIndent";
public static String equalsIndentKey = "equalsIndent";
public static String spaceCharKey = "spaceChar";
public static String newlineCharKey = "newlineChar";
public static String multiplyCharKey = "multiplyChar";
public static String divideCharKey = "divideChar";
public static String plusCharKey = "plusChar";
public static String equalsCharKey = "equalsChar";
public static String subjectCharKey = "subjectChar";
public static String thusCharKey = "thusChar";
HERE'S THE PROBLEM:
The top line of the textfile 'screws up' in the dictionary.
It is added to the dictionary and appears correctly amongst the keySet and the printed format of the dictionary, but trying to access it returns "null".
(In this case, it's variableIndent. If I put variableIndent somewhere else in the text file, equalsIndent screws up, etc)
What's going on!?
Do I have a dodgy function?!
They've worked well for everything else.
Thanks!
change you UTF-8 text file which contains the key and value to UTF-8 without BOM.
There are three bytes(UTF-8 BOM 0xEF,0xBB,0xBF before "variableIndent")
see http://en.wikipedia.org/wiki/Byte_order_mark
If you are afraid of encoding issues (that seems to be the problem here), you have to make sure your project's encoding is set to UTF-8. To check it, go to Project menu, and choose Properties. It may be required to change text file encoding from Inherited from container to Oher: UTF-8
Hmm try this code and let us know the output
for (String key : characterDictionary.keySet() ) {
System.out.println(key);
}
for ( String value : characterDictionary.values() ) {
System.out.println(value);
}
P.S: Might want to change Type of key and value.
I suggest you look at your code in a debugger. I suspect the map is not what you think it is.
String data = "{thusChar=∴, spaceChar= , plusChar=+, equalsIndent=#, multiplyChar=×, equalsChar==, newlineChar=\\n, divideChar=÷, subjectChar=:, variableIndent=#}";
Map<String, String> map = new LinkedHashMap<String, String>();
for (String keyValue : data.substring(1, data.length() - 1).split(", ")) {
String[] parts = keyValue.split("=", 2);
map.put(parts[0], parts[1]);
}
System.out.println("variableIndent is " + map.get("variableIndent"));
prints
variableIndent is #
can you try
for(String key: map.keySet())
System.out.println("'"+key+"'= "+map.get(key));
Try it this way...
Map<String, String> map = new LinkedHashMap<String, String>();
for (Map.Entry<String, String> mp : map.entrySet()){
System.out.println("Key: "+mp.key()+"::"+"Value: "+mp.value());
}
If you think it's an encoding issue, then try using the following methods to compare the actual content, irrespective of what it looks like.
Use getBytes() to get all the bytes from both Strings (the key from the map, as well as the string in your code), and print
The length of the byte array
Each byte as an integer
Then use getChars() to get all the chars from both Strings or charAt() to read each char, and print
Each char as an integer.
Between these two checks you should be able to figure out how both strings are different at a byte level. What's the character-set that the file is saved in?
EDIT
I suspect your use of DataInputStream is causing problems with the bytes being read.
InputStream fstream = FileManager.class.getResourceAsStream(ResourceFile);
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
The Java docs for DataInputStream say "A data input stream lets an application read primitive Java data types from an underlying input stream in a machine-independent way. An application uses a data output stream to write data that can later be read by a data input stream." You're not reading from a DataOutputStream here, just a regular file.
Also, you already have an InputStream for the InputStreamReader to use. Change your code to this:
InputStream fstream = FileManager.class.getResourceAsStream(ResourceFile);
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
EDIT 2
Another thing worth doing, since your string from the text file is 3 bytes longer, is changing this
BaseUnitsCache.put(currentLine.get(0), currentLine.get(1));
to
BaseUnitsCache.put(currentLine.get(0).trim(), currentLine.get(1).trim());
I have a program that loads lines from a user file, then selects the last part of the String (which would be an int)
Here's the style it's saved in:
nameOfValue = 0
nameOfValue2 = 0
and so on. I have selected the value for sure - I debugged it by printing. I just can't seem to save it back in.
if(nameOfValue.equals(type)) {
System.out.println(nameOfValue+" equals "+type);
value.replace(value, Integer.toString(Integer.parseInt(value)+1));
}
How would I resave it? I've tried bufferedwriter but it just erases everything in the file.
My suggestion is, save all the contents of the original file (either in memory or in a temporary file; I'll do it in memory) and then write it again, including the modifications. I believe this would work:
public static void replaceSelected(File file, String type) throws IOException {
// we need to store all the lines
List<String> lines = new ArrayList<String>();
// first, read the file and store the changes
BufferedReader in = new BufferedReader(new FileReader(file));
String line = in.readLine();
while (line != null) {
if (line.startsWith(type)) {
String sValue = line.substring(line.indexOf('=')+1).trim();
int nValue = Integer.parseInt(sValue);
line = type + " = " + (nValue+1);
}
lines.add(line);
line = in.readLine();
}
in.close();
// now, write the file again with the changes
PrintWriter out = new PrintWriter(file);
for (String l : lines)
out.println(l);
out.close();
}
And you'd call the method like this, providing the File you want to modify and the name of the value you want to select:
replaceSelected(new File("test.txt"), "nameOfValue2");
I think most convenient way is:
Read text file line by line using BufferedReader
For each line find the int part using regular expression and replace
it with your new value.
Create a new file with the newly created text lines.
Delete source file and rename your new created file.
Please let me know if you need the Java program implemented above algorithm.
Hard to answer without the complete code...
Is value a string ? If so the replace will create a new string but you are not saving this string anywhere. Remember Strings in Java are immutable.
You say you use a BufferedWriter, did you flush and close it ? This is often a cause of values mysteriously disappearing when they should be there. This exactly why Java has a finally keyword.
Also difficult to answer without more details on your problem, what exactly are you trying to acheive ? There may be simpler ways to do this that are already there.
How can I read a file easily in Java if I have following file format:
a|dip
a|dop
c|nap
a|dip
b|dop
b|sip
a|tang
c|dig
c|nap
I want to get all words that belongs to "a", "b", and "c". What data structure I can use to read and store this information?
You can also suggest some good file formats (two column) that is easy to read/write in Java.
I know some of you may be thinking that what is the real problem that I want to solve, I have some complex employee related data. Current (poor) system generate some files and I am trying to process them to add them in database. The current files' format is bit complex (private), I cannot copy past here.
If you can use Google Guava (http://code.google.com/p/guava-libraries/) then you'll get a few handy classes (you can use some or all of these):
com.google.common.io.Files
com.google.common.io.LineProcessor<T>
com.google.common.base.Charsets
com.google.common.collect.Multimap<K,V>
com.google.common.collect.ArrayListMultimap<K,V>
For example you could write:
LineProcessor<Multimap<String, String>> processor =
new LineProcessor<Multimap<String, String>>() {
Multimap<String, String> processed = ArrayListMultimap.create();
public boolean processLine(String line) {
String parts[] = line.split("\\|", 2); // 2 keeps any | in the rest of the line
processed.put(parts[0], parts[1]);
return true; // keep going
}
public Multimap<String, String> getResult() {
return processed;
}
};
Multimap<String, String> result = Files.readLines(
new File("filename.txt"), Charsets.UTF_8, processor);
You can use Scanner to read the text file one line at a time and then you can use String.split("\\|") to separate the parts on that line. For storing the information, a Map<String,List<String>> might work.
I'd use this data structure:
Map<String, List<String>> map = new HashMap<String, List<String>>();
And parse the file like this:
File file = new File("words.txt");
Scanner scanner = new Scanner(file);
while (scanner.hasNext()) {
String next = scanner.next();
String[] parts = next.split("\\|");
String group = parts[0];
String word = parts[1];
List<String> list = map.get(group);
if (list == null) {
list = new ArrayList<String>();
map.put(group, list);
}
list.add(word);
}
So you could get the list of words for "a" like so:
for (String word : map.get("a")) {
System.out.println(word);
}
currently i creating a java apps and no database required
that why i using text file to make it
the structure of file is like this
unique6id username identitynumber point
unique6id username identitynumber point
may i know how could i read and find match unique6id then update the correspond row of point ?
Sorry for lack of information
and here is the part i type is
public class Cust{
string name;
long idenid, uniqueid;
int pts;
customer(){}
customer(string n,long ide, long uni, int pt){
name = n;
idenid = ide;
uniqueid = uni;
pts = pt;
}
FileWriter fstream = new FileWriter("Data.txt", true);
BufferedWriter fbw = new BufferedWriter(fstream);
Cust newCust = new Cust();
newCust.name = memUNTF.getText();
newCust.ic = Long.parseLong(memICTF.getText());
newCust.uniqueID = Long.parseLong(memIDTF.getText());
newCust.pts= points;
fbw.write(newCust.name + " " + newCust.ic + " " + newCust.uniqueID + " " + newCust.point);
fbw.newLine();
fbw.close();
this is the way i text in the data
then the result inside Data.txt is
spencerlim 900419129876 448505 0
Eugene 900419081234 586026 0
when user type in 586026 then it will grab row of eugene
bind into Cust
and update the pts (0 in this case, try to update it into other number eg. 30)
Thx for reply =D
Reading is pretty easy, but updating a text file in-place (ie without rewriting the whole file) is very awkward.
So, you have two options:
Read the whole file, make your changes, and then write the whole file to disk, overwriting the old version; this is quite easy, and will be fast enough for small files, but is not a good idea for very large files.
Use a format that is not a simple text file. A database would be one option (and bear in mind that there is one, Derby, built into the JDK); there are other ways of keeping simple key-value stores on disk (like a HashMap, but in a file), but there's nothing built into the JDK.
You can use OpenCSV with custom separators.
Here's a sample method that updates the info for a specified user:
public static void updateUserInfo(
String userId, // user id
String[] values // new values
) throws IOException{
String fileName = "yourfile.txt.csv";
CSVReader reader = new CSVReader(new FileReader(fileName), ' ');
List<String[]> lines = reader.readAll();
Iterator<String[]> iterator = lines.iterator();
while(iterator.hasNext()){
String[] items = (String[]) iterator.next();
if(items[0].equals(userId)){
for(int i = 0; i < values.length; i++){
String value = values[i];
if(value!=null){
// for every array value that's not null,
// update the corresponding field
items[i+1]=value;
}
}
break;
}
}
new CSVWriter(new FileWriter(fileName), ' ').writeAll(lines);
}
Use InputStream(s) and Reader(s) to read file.
Here is a code snippet that shows how to read file.
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("c:/myfile.txt")));
String line = null;
while ((line = reader.readLine()) != null) {
// do something with the line.
}
Use OutputStream and Writer(s) to write to file. Although you can use random access files, i.e. write to the specific place of the file I do not recommend you to do this. Much easier and robust way is to create new file every time you have to write something. I know that it is probably not the most efficient way, but you do not want to use DB for some reasons... If you have to save and update partial information relatively often and perform search into the file I'd recommend you to use DB. There are very light weight implementations including pure java implementations (e.g. h2: http://www.h2database.com/html/main.html).