Ok, I'm really confused by some code I wrote. It's a DataSetter (didn't know a better name for it...), and has methods to change the data in my data file (data.txt). This data has the following format: #key=value (eg. #version=1.0). Now, I tried to run this line of code:
new DataSetter().setValue("version", "1.1");
It just clears the file. That's pretty much all it does. Now, I think it clears the file because it makes a new File, which is completely empty but has the same name. Here's my code:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
/**
* This class contains methods to set specific data in the data.txt file. <br>
* The data is rewritten every time a new value is set.
*
* #author Casper van Battum
*
*/
public class DataSetter {
private static final File DATA_FILE = new File("resources/data.txt");
private static final String lineFormat = "#%s=%s";
private FileOutputStream out;
private DataReader reader = new DataReader();
private HashMap<String, String> dataMap = reader.getDataMap();
private Scanner scanner;
public DataSetter() {
try {
out = new FileOutputStream(DATA_FILE, false);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public void setValue(String key, String newValue) {
openDataFile();
String oldLine = String.format(lineFormat, key, dataMap.get(key));
dataMap.put(key, newValue);
String newLine = String.format(lineFormat, key, newValue);
try {
replace(oldLine, newLine);
} catch (IOException e) {
e.printStackTrace();
}
closeDataFile();
}
private void replace(String oldLine, String newLine) throws IOException {
ArrayList<String> tmpData = new ArrayList<String>();
while (scanner.hasNextLine()) {
String currentLine = scanner.nextLine();
tmpData.add((currentLine == oldLine) ? newLine : currentLine);
}
out.write(new String().getBytes());
String sep = System.getProperty("line.separator");
StringBuffer sb = new StringBuffer();
for (String string : tmpData) {
sb.append(string + sep);
}
FileWriter writer = new FileWriter(DATA_FILE);
String outString = sb.toString();
writer.write(outString);
writer.close();
}
private void openDataFile() {
try {
scanner = new Scanner(DATA_FILE);
} catch (FileNotFoundException ex) {
ex.printStackTrace();
}
}
private void closeDataFile() {
scanner.close();
}
}
So after running the setValue() method, I just have an empty file...
Im really out of idea's on how to solve this...
You are truncating your data file with the
new FileOutputStream(DATA_FILE, false)
so no nothing is written when you go to output your the elements in the tmpData ArrayList read from Scanner.
ArrayList<String> tmpData = new ArrayList<String>();
while (scanner.hasNextLine()) {
String currentLine = scanner.nextLine(); // never gets called
...
}
The typical strategy for updating a text file is to create a temporary file with old file's contents (File#renameTo), write the data to file, then delete the temporary file after closing any open streams to the file being read.
Related
I have a record in a CSV file and i am trying to add some extra info (a name) to the same specific record with the following code but it does not work. There is no error shown but the info i am trying to add just does not appear. What am i missing ?
public class AddName {
public static void main(String[] args) {
String filepath="Zoo.csv";
String editTerm="Fish";
String addedName="Ron";
addToRecord(filepath,editTerm,addedName);
}
public static void addToRecord(String filepath,String editTerm,String addedName){
String animal= "";
try{
FileWriter fw=new FileWriter(filepath,true);
BufferedWriter bw=new BufferedWriter(fw);
PrintWriter pw=new PrintWriter(bw);
if (animal.equals(editTerm)){
pw.println(editTerm+","+addedName);
pw.flush();
pw.close();
}
System.out.println("Your Record was saved");
}
catch(Exception e){
System.out.println("Your Record was not saved");
e.printStackTrace();
}
}
You could consider using a CSV library to help you out with parsing CSVs because it is more complicated than it looks, especially when it comes down to quoting.
Here's a quick example using OpenCSV that clones the original CSV file and adds "Ron" as necessary:
public class Csv1 {
public static void main(String[] args) throws IOException, CsvValidationException {
addToRecord("animal.csv", "animal-new.csv", "fish", "Ron");
}
public static void addToRecord(String filepathIn, String filepathOut, String editTerm, String addedName)
throws IOException, CsvValidationException {
try (CSVReader reader = new CSVReader(new FileReader(filepathIn))) {
try (CSVWriter writer = new CSVWriter(new FileWriter(filepathOut))) {
String[] values;
while ((values = reader.readNext()) != null) {
if (values.length > 2 && values[0].equals(editTerm)) {
values[1] = addedName;
}
writer.writeNext(values);
}
}
}
}
}
Given the file:
type,name,age
fish,,10
cat,,12
lion,tony,10
will produce:
"type","name","age"
"fish","Ron","10"
"cat","","12"
"lion","tony","10"
(You can look for answers about outputting quotes in the resulting CSV)
Here the requirement is to add an extra column if the animal name matches. It's equivalent to changing a particular line in a file. Here's a simple approach to achieve the same, (Without using any extra libraries),
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class EditLineInFile {
public static void main(String[] args) {
String animal = "Fish";
Path path = Paths.get("C:\\Zoo.csv");
try {
List<String> allLines = Files.readAllLines(path);
int counter = 0;
for (String line : allLines) {
if (line.equals(animal)) {
line += ",Ron";
allLines.set(counter, line);
}
counter++;
}
Files.write(path, allLines);
} catch (IOException e) {
e.printStackTrace();
}
}
}
You may use this code to replace the file content "Fish" to "Fish, Ron"
public static void addToRecord(String filepath, String editTerm, String addedName) {
try (Stream<String> input = Files.lines(Paths.get(filepath));
PrintWriter output = new PrintWriter("Output.csv", "UTF-8"))
{
input.map(s -> s.replaceAll(editTerm, editTerm + "," + addedName))
.forEachOrdered(output::println);
} catch (IOException e) {
e.printStackTrace();
}
}
I am attempting to read a text file that I created using another code to fill out a map however the scanner keeps on stopping early, however if I remove the line in the text doc where it stops the scanner will continue on for a while before getting stuck again. I can't see why it would be getting stuck on certain lines though. I added a link to the text doc that I am scanning through. For instance no matter when it is written the first instance of the castlevania line will clog up the system, in the doc it shows up at line 307. If that line is removed it crahses at stops at Conta on line 383. Then if that is removed it breaks at Dig Dug on line 479. It continues in this way of stopping on random lines that seem to have no relation, in name or line number.
TextDocDownload
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;
public class Read {
public static PrintWriter writer;
public static Map<String, LinkedHashMap<String, String>> connectionsMap = new LinkedHashMap<String, LinkedHashMap<String,String>>() ;
public static void main(String[] args) {
setUp();
Iterator it = connectionsMap.entrySet().iterator();
int i =0;
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
System.out.println(pair.getKey() +" "+i);
i++;
it.remove(); // avoids a ConcurrentModificationException
}
}
public static void setUp() {
File file = new File("Degrees.txt");//file with all the connections
try {
Scanner scanner = new Scanner(file);
String description = "";
String key="";//key for map of main series
String secondKey="";//key for map of a mian serieses connections
String text = "";
while(scanner.hasNext()) {
String see = scanner.next();
if(see.equals("TITLEEND")) {
key=text;
text="";
}
if(see.equals("CONNECTIONTITLEEND")) {
secondKey=text;
text="";
}
if(see.equals("DESCRIPTIONEND")||see.equals("TERMINATE")) {
description =text;
text="";
mapMaker(key,secondKey,description, false);
}if(!see.equals("TERMINATE")&&!see.equals("CONNECTIONTITLEEND")&&!see.equals("DESCRIPTIONEND")&&!see.equals("TITLEEND")) {
if(text.length()<1)text=see;
else text+=" "+see;
}
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void mapMaker(String key, String secondKey, String description, boolean recursed) {
if(!connectionsMap.containsKey(key)) {
connectionsMap.put(key, new LinkedHashMap<String,String>());
}if(!connectionsMap.get(key).containsKey(secondKey)) {
connectionsMap.get(key).put(secondKey, description);
}
if(!recursed) {
mapMaker(secondKey,key,description,true);
}
}
I cannot figure out how to make this txt file with numbers into an array, I am able to get it to read and print the screen but I need to be able to organize the numbers and delete the duplicates. This is what my code looks like so far
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class File {
public static void main(String[] args) {
String filename = "C:/input.txt";
File rfe = new File();
rfe.readFile(filename);
}
private void readFile(String name) {
String input;
try (BufferedReader reader = new BufferedReader(new FileReader(name))) {
while((input = reader.readLine()) != null) {
System.out.format(input); // Display the line on the monitor
}
}
catch(FileNotFoundException fnfe) {
}
catch(IOException ioe) {
}
catch(Exception ex) { // Not required, but a good practice
}
}
}
I would recommend using an ArrayList rather than an Array.
With an array you would have to parse through the list and calculate the line count before you could even initialize it. An ArrayList is much more flexible as you don't have to declare how many values will be added to it.
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class File {
private List<Integer> data = new ArrayList<Integer>(); //Create ArrayList
public static void main(String[] args) {
String filename = "C:/input.txt";
File rfe = new File();
rfe.readFile(filename);
}
private void readFile(String name) {
String input;
try (BufferedReader reader = new BufferedReader(new FileReader(name))) {
while((input = reader.readLine()) != null) {
data.add(Integer.parseInt(input));//Add each parsed number to the arraylist
System.out.println(input); // Display the line on the monitor
}
}
catch(FileNotFoundException fnfe) {
}
catch(IOException ioe) {
}
catch(Exception ex) { // Not required, but a good practice
ex.printstacktrace(); //Usually good for general handling
}
}
}
How would I go about saving a String Vector to a file every time it is edited?
So let's say I have usernames in a vector, after I add or delete a username I'd like it to save that vector so if the program is closed, it will show the most recent elements.
This should help you get started.
As JB Nizet said, you should use an ArrayList.
I also went ahead and used Java 7 autocloseable functionality, which ensures you close file handles appropriately.
Of course, you will need to validate your input, and you will want to take care about what you persist. I suspect that you will soon want to consider a better storage strategy, however, this will get you started.
In addition, since this is acting like a collection, you should add hashcode and equals. For brevity sake, I did not add those.
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
public class PersistedCollection {
private static final String NEWLINE_SEPARATOR = System.getProperty("line.separator");
private final List<String> values;
private final File file;
public PersistedCollection(File file) {
this.values = new ArrayList<>();
this.file = file;
}
public void add(String value) {
// You should validate this value. Remove carriage returns, make sure it meets your value specifications.
values.add(value);
persist();
}
public void remove(String value) {
values.remove(value);
persist();
}
private void persist() {
// Using Java 7 autocloseable to ensure that the output stream is closed, even in exceptional circumstances.
try (OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(this.file), 8192); Writer writer = new PrintWriter(outputStream)) {
for (String value : values) {
writer.append(value);
writer.append(NEWLINE_SEPARATOR);
}
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("PersistedCollection [values=");
builder.append(values);
builder.append(", file=");
builder.append(file);
builder.append("]");
return builder.toString();
}
public static void main(String[] arguments) {
PersistedCollection persistedCollection = new PersistedCollection(new File("/tmp/test.txt"));
persistedCollection.add("jazeee");
persistedCollection.add("temporary user");
persistedCollection.add("user402442");
persistedCollection.add("JB Nizet");
persistedCollection.remove("temporary user");
System.out.println(persistedCollection);
}
}
Another solution would be to create a class where you add all the methods required to read from a file of usernames (one username per line). Then you can refer to this class from anywhere (as the modifier is public) and call the methods such that you will add or remove usernames from that file.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.io.File;
public class Test {
private static BufferedWriter bw;
private static ArrayList<String> vector=new ArrayList<String>();
private static String everything;
//add an username
public static void add(String x){
vector.add(x);
}
//remove an username
public static void remove(String x){
vector.remove(x);
}
//update the file with the new vector of usernames
public static void updateToFile() throws IOException{
File username = new File("/home/path/to/the/file");
FileWriter fw = new FileWriter(username.getAbsoluteFile());
bw= new BufferedWriter(fw);
for (String x:vector){
bw.write(x.toString());
bw.write("\n");
}
bw.close();
}
//you call this method to initialise your vector of usernames
//this implies that you already have a file of usernames
//one username per line
public static void setUsername() throws IOException{
vector=new ArrayList<String>();
BufferedReader br = new BufferedReader(new FileReader("/home/path/to/the/file"));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
everything = sb.toString();
} finally {
br.close();
}
String lines[] = everything.split("\\r?\\n");
for (String x:lines){
vector.add(x);
}
}
//print your usernames in the console
public static void printUsers(){
for (String User:vector){
System.out.println(User);
}
}
}
Then it gets as easy as this:
import java.io.IOException;
public class MainTest {
public static void main(String[] args) throws IOException{
Test.setUsername();
Test.printUsers();
Test.add("username5");
Test.remove("username2");
System.out.println("// add username5; remove username2");
Test.printUsers();
System.out.println("// file has been updated with the new state");
Test.updateToFile();
System.out.println("// veryfing update");
Test.setUsername();
Test.printUsers();
}
}
The output:
(this first 4 users is what I have in the file)
username1
username2
username3
username4
// add username5; remove username2
username1
username3
username4
username5
// file has been updated with the new state
// verifying update
username1
username3
username4
username5
Trying to read a file when the user enters the file name into the console. The program compiles and runs with no errors. Once you enter the file name and press enter, you get this error. Can't figure out why. Any help would be appreciated.
Exception in thread "main" java.lang.NullPointerException
at java.io.Writer.<init>(Writer.java:88)
at java.io.PrintWriter.<init>(PrintWriter.java:113)
at java.io.PrintWriter.<init>(PrintWriter.java:100)
at propertylistings.propertylistings.main(propertylistings.java:34)
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.TreeSet;
public class propertylistings {
public static void main(String[] args)
throws FileNotFoundException
{
// Prompt for the input file name
Scanner console = new Scanner(System.in);
System.out.print("Input file: ");
String inputFileName = console.next();
BufferedWriter pwfo = null;
try {
pwfo = new BufferedWriter(new FileWriter("C:\\agentReport.txt",
true));
} catch (IOException e) {
}
//next line is LINE 34
PrintWriter pwo = new PrintWriter(pwfo);
// Construct property type treeSet
Set<String> propertyTypes = pTypes(inputFileName);
// Print property types from treeSet
for (String type : propertyTypes) {
System.out.println(type);
pwo.println(type);
}
// Construct agent ids and values treeSet
Set<String> agentRpt = agentValue(inputFileName);
// Print agent Ids and values from key set
for (String tail : agentRpt) {
{
System.out.println(tail);
pwo.println(tail);
}
}
pwo.flush();
pwo.close();
}
// Reads the input file.
// #return the alphabetized property types in uppercase.
public static Set<String> pTypes(String inputFileName)
throws FileNotFoundException
// Construct a tree set to return property types
{
Set<String> type = new TreeSet<String>();
Scanner in = new Scanner(new File(inputFileName));
// Use delimiters to select specific chars for set
in.useDelimiter("[1234567890. ]");
while (in.hasNext()) {
type.add(in.next().toUpperCase());
}
in.close();
return type;
}
// Reads the input file.
// #returns the Agent id's and corresponding property values.
public static Set<String> agentValue(String inputFileName)
throws FileNotFoundException {
TreeSet<String> tail = new TreeSet<String>();
SortedMap<String, Number> agentValues = new TreeMap<String, Number>();
Scanner in = new Scanner(new File(inputFileName));
String line = inputFileName;
while (in.hasNextLine()) {
try {
line = in.nextLine();
String[] fields = line.split("[\\s}]");
String agentId = (fields[3]);
Double pValue = Double.parseDouble(fields[2]);
if (agentValues.containsKey(agentId)) {
pValue += agentValues.get(agentId).doubleValue();
}
agentValues.put(agentId, pValue);
} catch (Exception e) {
}
// Create keyMap with all keys and values
Set<String> keySet = agentValues.keySet();
for (String key : keySet) {
Number value = agentValues.get(key);
// System.out.println(key + ":" + value);
tail.add(key + ":" + value);
}
}
return tail;
}
}
Put a stacktrace in your catch block and you'll know the exact error.
try {
pwfo = new BufferedWriter(new FileWriter("C:\\agentReport.txt", true));
} catch (IOException e) {
e.printstacktrace();
}