Saving Stats with Java IO - java

I have a file and a basic reader and writer set up but when I change the value it doesn't write the new value
Here's the code:
int constitutionLevel, strengthLevel;
int[] saveStats = { constitutionLevel, strengthLevel };
int constitutionLevelLocation = 0;
int strengthLevelLocation = 1;
public StatSaver()
{
constitutionLevel = Constitution.getConstitutionLevel();
strengthLevel = Strength.getStrengthLevel();
}
public void startSaving()
{
readPlayer("SaveManagement/Stats/save.txt");
updatePlayerStats();
savePlayer("SaveManagement/Stats/save.txt");
}
private void updatePlayerStats()
{
System.out.println("Saving Stats...");
System.out.println(constitutionLevel);
constitutionLevel = saveStats[constitutionLevelLocation];
strengthLevel = saveStats[strengthLevelLocation];
System.out.println(constitutionLevel);
System.out.println("Done Saving Stats");
}
private void readPlayer(String filePath)
{
File inputFile;
BufferedReader inputReader;
try
{
inputFile = new File(filePath);
inputReader = new BufferedReader(new FileReader(inputFile));
for (int i = 0; i < saveStats.length; i++)
{
saveStats[i] = Integer.parseInt(inputReader.readLine());
}
inputReader.close();
} catch (Exception e) { e.printStackTrace(); }
}
private void savePlayer(String filePath)
{
File outputFile;
BufferedWriter outputWriter;
try
{
outputFile = new File(filePath);
outputWriter = new BufferedWriter(new FileWriter(outputFile));
outputWriter.write(saveStats[0] + "\n");
outputWriter.write(saveStats[1] + "\n");
//for (int i = 0; i < saveStats.length; i++)
//{
// outputWriter.write(saveStats[i] + "\n");
//}
outputWriter.close();
} catch (Exception e) { e.printStackTrace(); }
}
As you can see I have a line of code commented out but the two lines of code right above do the same thing I just have to type a few more things, I could change it for something bigger but since I have two stats right now I am not in any rush. The only solution that is short term would be to change the value in the .txt file but that would not work when I public the game because everybody would put the stat at infinity. Anyways please help and Thanks in advance!

So, in your startSaving() method, you read in information from readPlayer() (which I assume is the old values stored in the file), and then place the values into the array. In the updatePlayerStats(), you take the values in the array, and put them into the two variables (overwriting what was placed in them by the constructor). Lastly, the savePlayer() method takes the information from the array, and saves them into the file. At no point did you change the values in the array, so no new numbers are being added to the file.

Related

how can I write a code to read each name in a file

I typed 3 names in the file, and I wanted to write a code to count how many times each name was repeated (Example: Alex was repeated in the file 3 times..and so on). The code I wrote only counted each name once, and this is wrong because the names were repeated more than once. Can you help me with the part that could be the cause of this problem?
public class MainClass {
public static void readFile() throws IOException {
//File file;
FileWriter writer=null;
String name, line;
List <String> list = new ArrayList <>();
int countM = 0, countAl = 0, countAh = 0;
try
{
File file = new File("\\Users\\Admin\\Desktop\\namesList.txt");
Scanner scan = new Scanner(file);
while(scan.hasNextLine()) {
line = scan.nextLine();
list.add(line);
}
for (int i=0; i<list.size(); i++)
{
name=list.get(i);
if (name.equals("Ali"))
{
countAl= +1;
}
if (name.equals("Ahmed"))
{
countAh= +1;
}
if (name.equals("Muhammad"))
{
countM = +1;
}
}
Collections.sort(list);
writer = new FileWriter("\\Users\\Admin\\Desktop\\newNameList");
for(int i=0; i<list.size(); i++)
{
name = list.get(i);
writer.write(name +"\n");
}
writer.close();
System.out.println("How many times is the name (Ali) in the file? " + countAl);
System.out.println("How many times is the name (Ahmed) in the file? " + countAh);
System.out.println("How many times is the name (Muhammad) in the file? " + countM);
}
catch(IOException e) {
System.out.println(e.toString());
}
}
public static void main(String[] args) throws IOException {
readFile();
}
}
You an do this much simpler:
//Open a reader, this is autoclosed so you don't need to worry about closing it
try (BufferedReader reader = new BufferedReader(new FileReader("path to file"))) {
//Create a map to hold the counts
Map<String, Integer> nameCountMap = new HashMap<>();
//read all of the names, this assumes 1 name per line
for (String name = reader.readLine(); name != null; name = reader.readLine()) {
//merge the value into the count map
nameCountMap.merge(name, 1, (o, n) -> o+n);
}
//Print out the map
System.out.println(nameCountMap);
} catch (IOException e) {
e.printStackTrace();
}
try:
for (int i=0; i<list.size(); i++)
{
name=list.get(i);
if (name.equals("Ali"))
{
countAl += 1;
}
if (name.equals("Ahmed"))
{
countAh += 1;
}
if (name.equals("Muhammad"))
{
countM += 1;
}
}
This works with me.
+= is not same =+
You need to process each line bearing in mind that the file may be very large in some cases. Better safe than sorry. You need to consider a solution that does not take up so much resources.
Streaming Through the File
I'm going to use a java.util.Scanner to run through the contents of the file and retrieve lines serially, one by one:
FileInputStream inputStream = null;
Scanner sc = null;
try {
inputStream = new FileInputStream(file_path);
sc = new Scanner(inputStream, "UTF-8");
while (sc.hasNextLine()) {
String line = sc.nextLine();
// System.out.println(line);
}
// note that Scanner suppresses exceptions
if (sc.ioException() != null) {
throw sc.ioException();
}
} finally {
if (inputStream != null) {
inputStream.close();
}
if (sc != null) {
sc.close();
}
}
This solution will iterate through all the lines in the file – allowing for processing of each line – without keeping references to them – and in conclusion, without keeping them in memory:
Streaming With Apache Commons IO
The same can be achieved using the Commons IO library as well, by using the custom LineIterator provided by the library:
LineIterator it = FileUtils.lineIterator(your_file, "UTF-8");
try {
while (it.hasNext()) {
String line = it.nextLine();
// do something with line
}
} finally {
LineIterator.closeQuietly(it);
}
Since the entire file is not fully in memory – this will also result in pretty conservative memory consumption numbers.
BufferedReader
try (BufferedReader br = Files.newBufferedReader(Paths.get("file_name"), StandardCharsets.UTF_8)) {
for (String line = null; (line = br.readLine()) != null;) {
// Do something with the line
}
}
ByteBuffer
try (SeekableByteChannel ch = Files.newByteChannel(Paths.get("test.txt"))) {
ByteBuffer bb = ByteBuffer.allocateDirect(1000);
for(;;) {
StringBuilder line = new StringBuilder();
int n = ch.read(bb);
// Do something with the line
}
}
The above examples will process lines in a large file without iteratively, without exhausting the available memory – which proves quite useful when working with these large files.

bufferedReader readline=null

im trying to write a class where it would take a text file,reverse its contents and write it back. The way i want to do it is to write the lines in a String[] array,reverse the lines and then write the text back to the text file. Problem is, when I start writing to the String array, it writes off only nulls and i know the text file is not empty. Im using a copy of the BufferedReader to read the lines. I can't seem to understand where am i wrong. When I initialize the String array textFile like down in the code, i have no problems reversing, but when i use the
String[] textFile = new String[getNumberOfLines ()];
method, it doesnt work.
public void reverse() throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(WORK_FOLDER_LOCATION + FILE_NAME));
String[] textFile = new String[3];
try {
for (int i = 0; i < textFile.length; i++) {
textFile[i] = reader.readLine();
textFile[i] = reverseLine(textFile[i]);
}
} catch (IOException e) {
throw new IOException("There was a problem while operating with the reader.");
} finally {
reader.close();
}
writeReverseText(textFile);
}
private int getNumberOfLines(BufferedReader reader) throws IOException {
BufferedReader linesReader = reader;
int counter = 0;
try {
while (linesReader.readLine() != null) {
counter++;
}
linesReader.close();
} catch (IOException e) {
throw new IOException("There was a problem while counting the lines");
}
return counter;
}
private String reverseLine(String string) {
StringBuilder reversedString = new StringBuilder(string).reverse();
System.out.println(reversedString);
return reversedString.toString();
}
private void writeReverseText(String[] textFile) throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter(WORK_FOLDER_LOCATION + FILE_NAME));
for (int i = 0; i < textFile.length; i++) {
writer.append(textFile[i]);
writer.append(System.lineSeparator());
}
writer.close();
}
EDIT I managed to solve the issue but changing the getNumberOfLines() method:
private int getNumberOfLines() throws IOException {
BufferedReader linesReader = new BufferedReader(new FileReader(WORK_FOLDER_LOCATION + FILE_NAME));
Hope this helps to the others, i would love to know why the previous code didn't work.
Your getNumberOfLines() method will read all the data from the BufferedReader - so unless you start reading the file again, there's nothing to read, and the very first call to readLine() will return null.
However, instead of doing this, you'd be better off just reading the file once, and populating a List<String>. For example:
List<String> lines = new ArrayList<>();
String line;
while ((line = reader.readLine()) != null) {
lines.add(reverseLine(line));
}

How to check if txt file contains a String, if so don't duplicate it

So right now I'm making a mod in Minecraft where it takes everyones username from a server and adds it to a txt file, it works but the the problem is I don't want to duplicate the names when I use the command again. Nothing has worked so far. How would I check if the txt already contains the username, don't add it again? Thank you. Again, I need it to before writing another name to the list, check the txt file if it already contains the name, if so don't add it.
for (int i = 0; i < minecraft.thePlayer.sendQueue.playerInfoList.size(); i++) {
List playerList = minecraft.thePlayer.sendQueue.playerInfoList;
GuiPlayerInfo playerInfo = (GuiPlayerInfo) playerList.get(i);
String playerName = StringUtils.stripControlCodes(playerInfo.name);
try {
fileWriter = new FileWriter(GameDirectory() + "\\scraped.txt", true);
bufferedReader = new BufferedReader(new FileReader(GameDirectory() + "\\scraped.txt"));
lineNumberReader = new LineNumberReader(new FileReader(GameDirectory() + "\\scraped.txt"));
} catch (IOException e) {
e.printStackTrace();
}
printWriter = new PrintWriter(fileWriter);
try {
fileWriter.write(playerName + "\r\n");
lineNumberReader.skip(Long.MAX_VALUE);
} catch (IOException e) {
e.printStackTrace();
}
printWriter.flush();
}
addMessage("Scraped " + lineNumberReader.getLineNumber() + " usernames!");
EDIT: Really need an answer guys :( Thank you
EDIT: this is what I have now, but it's not even writing it anymore.
List playerList = minecraft.thePlayer.sendQueue.playerInfoList;
for (int i = 0; i < minecraft.thePlayer.sendQueue.playerInfoList.size(); i++) {
GuiPlayerInfo playerInfo = (GuiPlayerInfo) playerList.get(i);
String playerName = StringUtils.stripControlCodes(playerInfo.name);
String lines;
try {
if ((lines = bufferedReader.readLine()) != null) {
if (!lines.contains(playerName)) {
bufferedWriter.write(playerName);
bufferedWriter.newLine();
bufferedWriter.flush();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
int linenumber = 0;
try {
while (lineNumberReader.readLine() != null) {
linenumber++;
}
} catch (IOException e) {
e.printStackTrace();
}
The logic of your second piece of code is wrong. If you write out the pseudo-code of it, it's easy to see why:
Open a File Reader at the start of the file
For every Player on the server
Save the player name
Read the next line of the file
If we have not reached the end of the file
If the player name is not on this line of the file
Write the name of the player to the file
You need to read the entire file outside of the loop, and then check if the player exists anywhere in the file, not just if it happens to be on the line which is the same position as the player on the server.
The easiest way to do this is to keep the players in a list while you're processing, and read/write them to file, like this:
public static List<String> loadPlayerList() throws FileNotFoundException
{
final Scanner scanner = new Scanner(new File(GameDirectory() + "\\scraped.txt"));
final List<String> players = new ArrayList<>();
while(scanner.hasNextLine())
players.add(scanner.nextLine());
return players;
}
public static void writePlayersList(final List<String> players) throws IOException
{
try(final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream((GameDirectory() + "\\scraped.txt")))))
{
for(final String player : players)
{
writer.write(player);
writer.newLine();
}
}
}
public static void main(String[] args) throws IOException
{
final List<String> players = loadPlayerList();
for(final GuiPlayerInfo player : minecraft.thePlayer.sendQueue.playerInfoList)
{
final String playerName = StringUtils.stripControlCodes(player.name);
if(!players.contains(playerName))
players.add(playerName);
}
writePlayersList(players);
}

Java - How to write ArrayList Objects into txt file?

/** I have some methods likes add,display,sort,delete,and exit that implemented the ArrayList function. It works correctly, but the problem is that the objects that had been added were not saved on a .txt file, just the temporary objects. So I need to add them into text file,so that I can display and delete them later. Here's the part of the codes.
*/
public class testing {
public static void main(String[] args) {
String Command;
int index = 0;
Scanner input = new Scanner(System.in);
ArrayList<String> MenuArray = new ArrayList<String>();
boolean out = false;
while (!out) {
System.out.print("Enter your Command: ");
Command = input.nextLine();
// method ADD for adding object
if (Command.startsWith("ADD ") || Command.startsWith("add ")) {
MenuArray.add(Command.substring(4).toLowerCase());
// indexing the object
index++;
/** i stuck here,it won't written into input.txt
BufferedWriter writer = new BufferedWriter(new FileWriter(
"input.txt"));
try {
for (String save : MenuArray) {
int i = 0;
writer.write(++i + ". " + save.toString());
writer.write("\n");
}
} finally {
writer.close();
}*/
} else if (Command.startsWith("EXIT") || Comand.startsWith("exit")) {
out = true;
}
}
}
}
FileUtils#writeLines seems to do exactly what you need.
You can use ObjectOutputStream to write an object into a file:
try {
FileOutputStream fos = new FileOutputStream("output");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(MenuArray); // write MenuArray to ObjectOutputStream
oos.close();
} catch(Exception ex) {
ex.printStackTrace();
}

Merge the files into a new big file until the number of user id's become 10 Million

I have around 100 files in a folder. Each file will have data like this and each line resembles an user id.
960904056
6624084
1096552020
750160020
1776024
211592064
1044872088
166720020
1098616092
551384052
113184096
136704072
And I am trying to keep on merging the files from that folder into a new big file until the total number of user id's become 10 Million in that new big file.
I am able to read all the files from a particular folder and then I keep on adding the user id's from those files in a linkedhashset. And then I was thinking to see whether the size of hashset is 10 Million and if it is 10 million then write all those user id's to a new text file. Is that feasoible solution?
That 10 million number should be configurable. In future, If I need to change that 10 million 1o 50Million
then I should be able to do that.
Below is the code I have so far
public static void main(String args[]) {
File folder = new File("C:\\userids-20130501");
File[] listOfFiles = folder.listFiles();
Set<String> userIdSet = new LinkedHashSet<String>();
for (int i = 0; i < listOfFiles.length; i++) {
File file = listOfFiles[i];
if (file.isFile() && file.getName().endsWith(".txt")) {
try {
List<String> content = FileUtils.readLines(file, Charset.forName("UTF-8"));
userIdSet.addAll(content);
if(userIdSet.size() >= 10Million) {
break;
}
System.out.println(userIdSet);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Any help will be appreciated on this? And any better way to do the same process?
Continuing from where we left. ;)
You can use the FileUtils to write the file along with the writeLines() method.
Try this -
public static void main(String args[]) {
File folder = new File("C:\\userids-20130501");
Set<String> userIdSet = new LinkedHashSet<String>();
int count = 1;
for (File file : folder.listFiles()) {
if (file.isFile() && file.getName().endsWith(".txt")) {
try {
List<String> content = FileUtils.readLines(file, Charset.forName("UTF-8"));
userIdSet.addAll(content);
if(userIdSet.size() >= 10Million) {
File bigFile = new File("<path>" + count + ".txt");
FileUtils.writeLines(bigFile, userIdSet);
count++;
userIdSet = new LinkedHashSet<String>();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
If the purpose of saving the data in the LinkedHashSet is just for writing it again to another file then I have another solution.
EDIT to avoid OutOfMemory exception
public static void main(String args[]) {
File folder = new File("C:\\userids-20130501");
int fileNameCount = 1;
int contentCounter = 1;
File bigFile = new File("<path>" + fileNameCount + ".txt");
boolean isFileRequired = true;
for (File file : folder.listFiles()) {
if (file.isFile() && file.getName().endsWith(".txt")) {
try {
List<String> content = FileUtils.readLines(file, Charset.forName("UTF-8"));
contentCounter += content.size();
if(contentCounter < 10Million) {
FileUtils.writeLines(bigFile, content, true);
} else {
fileNameCount++;
bigFile = new File("<path>" + fileNameCount + ".txt");
FileUtils.writeLines(bigFile, content);
contentCounter = 1;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
You can avoid the use of the Set as intermediate storage if you write at the same time that you read from file. You could do something like this,
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
public class AppMain {
private static final int NUMBER_REGISTERS = 10000000;
private static String[] filePaths = {"filePath1", "filePaht2", "filePathN"};
private static String mergedFile = "mergedFile";
public static void main(String[] args) throws IOException {
mergeFiles(filePaths, mergedFile);
}
private static void mergeFiles(String[] filePaths, String mergedFile) throws IOException{
BufferedReader[] readerArray = createReaderArray(filePaths);
boolean[] closedReaderFlag = new boolean[readerArray.length];
PrintWriter writer = createWriter(mergedFile);
int currentReaderIndex = 0;
int numberLinesInMergedFile = 0;
BufferedReader currentReader = null;
String currentLine = null;
while(numberLinesInMergedFile < NUMBER_REGISTERS && getNumberReaderClosed(closedReaderFlag) < readerArray.length){
currentReaderIndex = (currentReaderIndex + 1) % readerArray.length;
if(closedReaderFlag[currentReaderIndex]){
continue;
}
currentReader = readerArray[currentReaderIndex];
currentLine = currentReader.readLine();
if(currentLine == null){
currentReader.close();
closedReaderFlag[currentReaderIndex] = true;
continue;
}
writer.println(currentLine);
numberLinesInMergedFile++;
}
writer.close();
for(int index = 0; index < readerArray.length; index++){
if(!closedReaderFlag[index]){
readerArray[index].close();
}
}
}
private static BufferedReader[] createReaderArray(String[] filePaths) throws FileNotFoundException{
BufferedReader[] readerArray = new BufferedReader[filePaths.length];
for (int index = 0; index < readerArray.length; index++) {
readerArray[index] = createReader(filePaths[index]);
}
return readerArray;
}
private static BufferedReader createReader(String path) throws FileNotFoundException{
BufferedReader reader = new BufferedReader(new FileReader(path));
return reader;
}
private static PrintWriter createWriter(String path) throws FileNotFoundException{
PrintWriter writer = new PrintWriter(path);
return writer;
}
private static int getNumberReaderClosed(boolean[] closedReaderFlag){
int count = 0;
for (boolean currentFlag : closedReaderFlag) {
if(currentFlag){
count++;
}
}
return count;
}
}
The way you're going, you likely may run out of memory, your are keeping an unnecessary record in userIdSet.
A slight modification that can improve your code is as follows:
public static void main(String args[]) {
File folder = new File("C:\\userids-20130501");
File[] listOfFiles = folder.listFiles();
// there's no need for the userIdSet!
//Set<String> userIdSet = new LinkedHashSet<String>();
// Instead I'd go for a counter ;)
long userIdCount = 0;
for (int i = 0; i < listOfFiles.length; i++) {
File file = listOfFiles[i];
if (file.isFile() && file.getName().endsWith(".txt")) {
try {
List<String> content = FileUtils.readLines(file, Charset.forName("UTF-8"));
// I just want to know how many lines there are...
userIdCount += content.size();
// my guess is you'd probably want to print what you've got
// before a possible break?? - You know better!
System.out.println(content);
if(userIdCount >= 10Million) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Like I noted, just a slight modification. It was not my intention to run a very detailed analysis on your code. I just pointed out a glaring mis-design.
Finally, where you stated System.out.println(content);, you might consider writing to file at that point.
If you will write to file one line at a time, you try-catch block may look like this:
try {
List<String> content = FileUtils.readLines(file, Charset.forName("UTF-8"));
for(int lineNumber = 0; lineNumber < content.size(); lineNumber++){
if(++userIdCount >= 10Million){
break;
}
// here, write to file... But I will use simple System.out.print for example
System.out.println(content.get(lineNumber));
}
} catch (IOException e) {
e.printStackTrace();
}
Your code can be improved in many ways, but I don't have time to do that. But I hope my suggestion can push you further to the front in the right track. Cheers!

Categories