EDIT: I am trying to create a "clicker" game, that loads the last recorded number from the data file.
I am working on a simple, one button game, it is a clicker game. Nothing fancy, just a JButton and a JLabel. I'm fairly new at the Java IO Class, so I don't know what's causing this to happen. I'm not getting any errors, but a random number, except the same number every time.
Write Method:
public static void write(long data) {
File file = new File("data.txt");
path = file.getAbsolutePath();
try {
PrintWriter writer = new PrintWriter(file);
writer.println(data);
writer.close();
} catch (IOException e) {
System.out.println(e);
}
}
Read Method:
public static long read() {
long data = 0;
try {
BufferedReader reader = new BufferedReader(new FileReader(path));
data = reader.read();
reader.close();
return data;
} catch (IOException e) {
System.err.format("Exception occurred trying to read '%s'.", path);
e.printStackTrace();
return 0;
}
}
Graphical User Interface:
public static void gui() {
. . .
// Declarations {
JFrame frame = new JFrame("Clicker");
JPanel panel = new JPanel();
JButton clickerButton = new JButton("Click");
JLabel amountOfClicks = new JLabel("Click to get started!");
// }
. . .
// * * * * * * * * * * *
panel.setLayout(new GridLayout(2, 0));
// Action {
clickerButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
if (read() >= 1) {
clickerCount = read() + 1;
amountOfClicks.setText("You have clicked: " + clickerCount + " times.");
write(clickerCount);
} else {
clickerCount = clickerCount + 1;
amountOfClicks.setText("You have clicked: " + clickerCount + " times.");
write(clickerCount);
}
}
});
// }
. . .
Also the random number I get (48), when I click the button it should increase by 1. But now since it starts at "48", first click: increases by 1. Second: 4. Third: 1. Then stops increasing. The reason why I'm wanting to write to a file is so, I can load the last recorded number.
Retrieving data from a Properties File:
Store Data
First create a Properties object and add data to it. You can think of it's behavior similar to a Map. Each key has an associated value that is stored. Unfortunately for your case, Properties only stores strings, but we can work around that:
Properties props = new Properties();
props.setProperty("SomeKey", "SomeValue"); // String => String
props.setProperty("AnotherKey", String.valueOf(123456L)); // String => String (Long)
And of course 123456L can be replaced with a variable that is a long (or any other primitive type). For non-primitives, you can use .toString(). (See notes at bottom for non-primitives)
To write the data to a file, you need a FileOutputStream:
FileOutputStream output = new FileOutputStream("config.properties");
And then to write to that file:
props.store(output, null);
If you open that file it is plain-text and you will see something that looks like this:
#Sun Jul 16 22:47:45 EST 2017
SomeKey=SomeValue
AnotherKey=123456
Read Data
Reading data is just the reverse, now we need a FileInputStream and we will call .load().
FileInputStream input = new FileInputStream("config.properties");
Properties props = new Properties();
props.load(input);
Now the final part is accessing the data, remember everything is a string.
String someKey = props.getProperty("SomeKey");
long anotherKey = Long.valueOf(props.getProperty("AnotherKey"));
And thats all there is to it.
You can use Long.parseLong(props.getProperty("AnotherKey")) instead of .valueOf().
For non primitives this is most likely NOT the way to go as everything is saved as strings. For non-primitives, look into Serializable
Related
I am trying to get a value from the first line of a csv file ( header excluded) store in Firebase Storage
Here is the code :
private String readFromCsv() {
StorageReference refCompteActifs = FirebaseStorage.getInstance().getReference().child("my_file").child("my_file.csv");
StorageReference gsReference = refCompteActifs.getStorage().getReferenceFromUrl("gs://test-8095e.appspot.com/my_file/my_filer.csv");
File localFile = null;
try {
localFile = File.createTempFile("my_file", ".csv");
} catch (IOException e) {
e.printStackTrace();
}
File finalLocalFile = localFile;
final String[] result = {null};
List<String> rows = new ArrayList<>();
gsReference.getFile(Objects.requireNonNull(localFile)).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
#Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
try {
CSVReader reader = new CSVReader(new FileReader("./data/user/0/com.example.test/cache/" + finalLocalFile.getName()), ',', '\'', 1);
String[] nextLine = null;
while ((nextLine = reader.readNext()) != null) {
System.out.println(nextLine[4] + "\n");
rows.add(nextLine[4]);
}
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < rows.size(); i++) {
result[0] = rows.get(i);
}
}
}
System.out.println(result[0] + "\n");
return result[0];
}
The console never write "System.out.println(result[0] + "\n");" result[0] is affected inside the onlistener but I can't access it outside of it.
Thank you for your Help
That is the expected behavior. The getFile API is an asynchronous operation, which means that it executes in the background while the rest of your code continues to run. Then when the operation is complete, your onSuccess is called with the result.
This is easiest to see if you add some logging:
Log.i("File", "1. Starting to load file");
gsReference.getFile(Objects.requireNonNull(localFile)).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
#Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
Log.i("File", "2. Loaded file");
}
}
Log.i("File", "3. Started to load file");
If you run this code it outputs:
Starting to load file
Started to load file
Loaded file
This is probably not what you expected, but it is working by design - and it does completely explain why your System.out.println(result[0] + "\n"); doesn't show the file contents: the file hasn't been loaded yet.
This is an incredibly common problem, as most I/O and network APIs are asynchronous these days. The solution is always the same: any code that needs the data that is asynchronously loaded has to be inside the onSuccess handler, be called from there, or otherwise synchronized.
This means for example that you can't return the value from the file, as the return runs before the load has completed, and you'll instead want to pass a callback to your readFromCsv function, very similar to the OnSuccessListener.
For more on this, I recommend reading:
getContactsFromFirebase() method return an empty list
Setting Singleton property value in Firebase Listener
more questions on losing the asynchronous value outside of a callback
Say the user runs SomeProgram.java to calculate a bunch of stuff. One of the things they want to keep track of is how many times this program has been run and output the current run number. This is how far I got but it resets each time.
public class SomeProgram
{
public volatile int counter = 1;
public int getNextRun()
{
return counter++;
}
//calculates a bunch of variable that get output to user
public static void main(String args[])
{
SomeProgram variable = new SomeProgram();
runNumber = variable.getNextRun();
System.out.println(runNumber + "Some bunch of calculations");
}
}
Can someone explain why this got downvoted?
Whenever the user stops running your program, you're going to lose any variables stored in memory, so you're going to have to store that value somewhere else. The easiest solution would be to store it in a local file.
If your business needs to know this number, you can have the program call home to a webserver every time it starts up - this prevents the user from modifying the file on their computer - but is far more complicated to set up, and some users might not appreciate this unexpected behavior.
Complete implementation which stores updated counter in a file, invoke it whenever you want a counter to increment (i.e. when program starts). When a file doesn't exist, it is created. This method returns updated counter or 0 if there was some IOException.
public static int updateCounter() {
String counterFileName = "counter.txt";
int counter = 0;
File counterFile = new File(counterFileName);
if (counterFile.isFile()) {
try (BufferedReader reader = new BufferedReader(new FileReader(counterFileName))) {
counter = Integer.parseInt(reader.readLine());
} catch (IOException e) {
e.printStackTrace();
return 0;
}
}
try (FileWriter writer = new FileWriter(counterFileName)) {
writer.write(String.valueOf(++counter));
} catch (IOException e) {
e.printStackTrace();
return 0;
}
return counter;
}
Writing to the local file is not a good idea. You'll have to implement locking mechanism on your local file, otherwise you'll suffer of race conditions in case of simultaneous start of several program instances.
Alternative idea is to log each run into a persistent storage. So if you write each run's date and time to the db, you'll be able to calculate number of runs for arbitrary time interval.
Actual implementation depends on your requirements
You can use a Properties file:
public void loadProperties(String fileName)
{
Properties props = new Properties();
InputStream is = null;
// First try loading from the current directory
try {
File f = new File(fileName);
is = new FileInputStream( f );
}catch ( Exception e ) {
is = null;
e.printStackTrace();
}
try {
if ( is == null ) {
// Try loading from classpath
is = getClass().getResourceAsStream("example.properties");
}
// Try loading properties from the file (if found)
props.load( is );
String counter1 = props.getProperty("COUNTER_RUN");
String counter2 = props.getProperty("COUNTER_OUTPUT");
counterRun = Integer.parseInt(counter1);
counterOutput = = Integer.parseInt(counter2);
}catch ( Exception e ) {
e.printStackTrace();
}
}
public void saveProperties(String fileName) {
try {
Properties props = new Properties();
props.setProperty("COUNTER_RUN", ""+counterRun );
props.setProperty("COUNTER_OUTPUT", ""+counterOutput );
File f = new File(fileName);
OutputStream out = new FileOutputStream( f );
props.store(out, "Config params");
} catch (Exception e ) { e.printStackTrace(); }
}
counterRun and counterOutput are global vars
File example.properties
#Config paramns
#Tue May 03 14:17:35 COT 2016
COUNTER_RUN=241
COUNTER_OUTPUT=123
Background
I'm keeping a relatively large text file in android storage, and appending to it periodically- while limiting the file's size to some arbitrary size (say 2MB)
Hopefully I'm missing a function somewhere, or hopefully there is a better way to do this process.
Currently, when the file a goes over that arbitrary size, I create a temporary file b, copy the relevant portion of the file a (more or less the substring of the file a starting at byte xxx where xxx is the number of bytes too large the file a would be if I wrote the next bit of data to the log) plus the current data, then overwrite the file a with the second file b.
This is obviously terribly inefficient...
Another solution that I'm not terribly fond of is to keep two files, and toggle between the two of them, clearing the next when the current is full, and switching to that file for output.
However, it would be suuuuuper handy if I could just do something like this
File A = new File("output");
A.chip(500);
or maybe
A.subfile(500,A.length()-500);
TLDR;
Is there a function or perhaps library available for Android that can remove a portion of a file?
Did you already take a look at RandomAccessFile? Though you cannot remove portions of a file you can seek any position within the file and even set the length. So if you detect your file grows too large, just grab the relevant portion and jump to the beginning. Set length to 0 and write the new data.
EDIT:
I wrote a small demo. It shows if the file size is limeted to 10 bytes. If you pass in the values 10 to 15 as strings and separate them with commas, after 10,11,12, the file is written from the beginning, so after 15 it reads 13,14,15
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final long MAX = 10;
private static final String FILE_TXT = "file.txt";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
for (int i = 10; i <= 15; i++) {
if (i > 10) {
writeToFile(",");
}
writeToFile(Integer.toString(i));
}
}
private void writeToFile(String text) {
try {
File f = new File(getFilesDir(), FILE_TXT);
RandomAccessFile file = new RandomAccessFile(f, "rw");
long currentLength = file.length();
if (currentLength + text.length() > MAX) {
file.setLength(0);
}
file.seek(file.length());
file.write(text.getBytes());
file.close();
} catch (IOException e) {
Log.e(TAG, "writeToFile()", e);
}
printFileContents();
}
private void printFileContents() {
StringBuilder sb = new StringBuilder();
try {
FileInputStream fin = openFileInput(FILE_TXT);
int ch;
while ((ch = fin.read()) != -1) {
sb.append((char) ch);
}
fin.close();
} catch (IOException e) {
Log.e(TAG, "printFileContents()", e);
}
Log.d(TAG, "current content: " + sb.toString());
}
}
I am trying to understand why my code is not writing the output to the textfile as I expect it to work. My program takes a filename as a command line argument, and prints some text to the file as well as the screen. It is a bit more complicated since it uses classes and objects to demonstrate how objects work. Can anyone help decipher why it is not writing to the file? Here's my code:-
public class Mamoonp3test {
public static void main(String[] args) throws Exception {
//Create array of 10 guitar (Mamoonp3) objects
final int NUMBER_OF_INSTANCES = 10;
Mamoonp3[] objectNames = new Mamoonp3[NUMBER_OF_INSTANCES];
try
{
String fileName = new String(args[0]);
for(int i=0; i<NUMBER_OF_INSTANCES; i++) {
objectNames[i] = new Mamoonp3(FileName);
System.out.println("This is guitar number: " + i);
objectNames[i].tuneGuitar();
objectNames[i].playGuitar();
objectNames[i].displayAcronym();
objectNames[i].stopGuitar();
System.out.println("---------------------------");
}
}
catch (Exception e)
{
System.out.println("please provide an input file");
System.out.println("Usage: java Mamoonp3test filename.txt");
}
}
}
import java.io.*;
public class Mamoonp3 {
final int NUMBER_OF_STRINGS = 6;
char[] stringNames = {'E','A','D','G','B','E'};
int[] stringNumbers = {6,5,4,3,2,1};
String[] stringPitch = {"Sixth","Fifth","Fourth","Third","Second","First"};
boolean isTuned;
boolean isPlaying;
String stringAcronym = new String("Even After Dinner Giant Boys Eat");
//create a PrintWriter for output
PrintWriter output;
public Mamoonp3(String fileName) throws Exception{
isTuned = false;
isPlaying = false;
// create target file
File targetFile = new File(fileName);
//create a PrintWriter for output
output = new PrintWriter(targetFile);
}
public void tuneGuitar() {
System.out.println("The guitar is now tuned.");
for (int i=0; i<NUMBER_OF_STRINGS; i++) {
System.out.println(stringNames[i] + " is string number " + stringNumbers[i] + " and ranked " + stringPitch[i] + " in pitch");
output.print(stringNames[i] + " is string number " + stringNumbers[i] + " and ranked " + stringPitch[i] + " in pitch");
output.close();
}
}
public void playGuitar() {
System.out.println("The guitar is now playing.");
output.print("The guitar is now playing.");
output.close();
}
public void stopGuitar() {
System.out.println("The guitar is now stoped.");
output.print("The guitar is now stoped.");
output.close();
}
public void displayAcronym() {
System.out.println("Always remember your string names!");
System.out.println("Heres a reminder: " + stringAcronym);
output.print("Always remember your string names!");
output.print("Heres a reminder: " + stringAcronym);
output.close();
}
}
You're setting the File of an object that you then do nothing with, that you're not writing with,
Mamoonp3 newObject = new Mamoonp3(fileName);
... and not setting the File in objects that you try to write with. Check which constructors you are using: every Manoop3 object created in the for loop. To see that this is so, check which constructors you're using
I suggest that you change your approach entirely.
Get all file input and output out of your Mamoonp3 class.
Instead, that class should concern itself with representing the state of the musical instrument, and nothing else.
Give the class a decent toString() override method.
I & O should go elsewhere in a separate class of its own.
Give your I&O class a method that allows you to pass Mamoonp3 objects into it so that they can be written.
As an aside, you almost never would use new String(anything). Just use args[0].
Always close your PrintWriter when you are done writing. This is likely causing your error.
Edit
Possibly another way to solve this:
Create a PrintWriter object in the main method.
Give your Manoop3 class a PrintWriter field and a constructor that takes this PrintWriter and sets its field with it.
Write with the PrintWriter in Manoop3, but don't close it.
Then close the PrintWriter in the main method when all Manoop3 objects have completed their use of it.
Let me preface this by saying that I'm extremely new to java. This is my eighth week in the class and I'm stuck on a project. Here is what I have so far:
import java.io.*;
public class Guitar {
// Initialize variables
boolean isPlaying;
boolean inTune;
char[] guitStrings = {'D', 'G', 'C', 'A'}; // Guitar strings
int numOfStrings = 4; // Number of strings the guitar has.
public void Guitar(){
isPlaying = false; // Guitar is not playing by default.
inTune = false; // Guitar is not tuned by default.
System.out.println("The guitar is not tuned and is not playing.");
}
public void isPlaying(){
System.out.println("Your guitar is now playing!");
isPlaying = true; // Set guitar to playing
}
public void inTune(){
System.out.println("Your guitar is now tuned!");
inTune = true; // Set guitar to tuned.
}
public void stopPlaying(){
isPlaying = false; // Set isPlaying to false.
System.out.println("Your guitar has finished playing!");
}
public void notes(){
System.out.println("The guitar has played a total of " + numOfStrings +
" strings and they are: " + guitStrings[0] + "," + guitStrings[1] + ","
+ guitStrings[2] + "," + guitStrings[3]);
}
public static void main(String[] args) throws IOException{
java.io.File file = new java.io.File("guitartest.txt");
if(file.exists()){
System.out.println("File already exists!");
System.exit(1);
}
// Create a file
java.io.PrintWriter output = new java.io.PrintWriter(file);
Guitar[] guit = new Guitar[10];
for (int i = 0; i < guit.length; i++){
guit[i] = new Guitar();
guit[i].Guitar();
guit[i].inTune();
guit[i].isPlaying();
guit[i].notes();
guit[i].stopPlaying();
}
}
}
This program does everything I need it to do, but we have one last step on the project. I must output this to a text file from the command line. I've changed the last bit of code to this:
public static void main(String[] args) throws IOException{
java.io.File file = new java.io.File("guitartest.txt");
if (file.exists()){
System.out.println("This file already exists!");
System.exit(1);
}
// Create a file
java.io.PrintWriter output = new java.io.PrintWriter(file);
Guitar[] guit = new Guitar[10]; // Create 10 instruments
for (int i = 0; i < guit.length; i++){
output.println(guit[i] = new Guitar());
output.println(guit[i].Guitar());
output.println(guit[i].inTune());
output.println(guit[i].isPlaying());
output.println(guit[i].notes());
output.println(guit[i].stopPlaying());
}
}
This compiles the codes, and displays the results I want in the console, but the text file guitartest.txt is completely blank. I am NOT looking for someone to complete this assignment for me, I'm just looking for any advice or resources you could point me to. Thank you very much!
PrintWriter is buffered, that means that the text you're writing to it is stored in its internal buffer before being actually written to the file. So you need to call a close() method when you're done writing, so that the PrintWriter object wrote the data to the file and closed it.
You can also call flush(), this may be useful if you want your data written now but also want to continue using the PrintWriter object.
After you're done writing
output.flush();
output.close();
The PrintWriter constructor that accepts a File is implemented as
public PrintWriter(File file) throws FileNotFoundException {
this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
false);
}
In other words, your outputs are being buffered and need to be flushed from time to time or all in one shot.
Call
output.flush();
or
output.close();
when you are finished using it.
You probably need to flush the output stream at the end, i.e. after the for loop in the main() method do
output.flush();
output.close();
You can include both of these calls in a try/catch block, for safety:
try {
output.flush();
output.close();
} catch (Exception e) {
e.printStackTrace();
}