BufferedReader reset fail after read to end of file - java

I have a BufferedReader wrapped on a file, I want to mark a place and use reset() later to get back to this position. I have read the java api, it states mark (readlimit), when read too many bytes, the reset will fail. So i figure I can set a large limit.
However if i have code
BufferedReader br=...;
br.mark(1024000); // large but not as large as file.
while(br.ready()){
//keep reading. to find some stuff.
}
//now the br.ready() is false
br.reset() // It will fail with mark invalid exception
I think the problem is when br reach end of file, the br is no longer ready, and reset fails....I can manage to keep reading until the 2nd last line and stop, but then how do I do that?
I found that an ugly solution would be using PushbackReader, to save all the stuff I read and push back after the while loop. I am wondering if there's a better solution.

I think you missed the documentation of mark() where it clearly states
Parameters:
readAheadLimit - Limit on the number of characters that may be read while still preserving the mark. After reading this many characters, attempting to reset the stream may fail.
so if you want to fully read the stream and reset() afterwards you need to call mark() with a parameter that is as least as big as the rest of your file.
But as the documentation for BufferedReader.html#mark(int) adds
A limit value larger than the size of the input buffer will cause a new buffer to be allocated whose size is no smaller than limit. Therefore large values should be used with care.
So if memory is a concern, consider if you can incorporate the search and other processing steps or reopen the source between both steps. Surely there is also a way to utilize FileChannel which has the ability to freely seek through any given file, but won't provide you with characters or strings.
You can maybe utilize getReadCharacters() and reopenAt(BigInteger) of this class (not properly tested drop-in replacement for BufferedReaders acting upon files):
import java.io.*;
import java.math.BigInteger;
import java.nio.charset.Charset;
/**
* Created by TheConstructor for http://stackoverflow.com/a/24620470/1266906.
*/
public class MarkableFileReader extends Reader {
/**
* Cached instance of {#link java.math.BigInteger} of value
* {#link Long#MAX_VALUE} (used in {#link #skip(java.math.BigInteger)})
*/
public static final BigInteger LONG_MAX_VALUE = BigInteger.valueOf(Long.MAX_VALUE);
/**
* Default value of {#link #reopenOnResetThreshold} (10 MiB)
*/
public static final int DEFAULT_REOPEN_ON_RESET_THRESHOLD = 10 * 1024 * 1024;
/**
* Initialize the line-reading-buffer to this size
*/
public static final int EXPECTED_LINE_LENGTH = 80;
private final File file;
private final Charset charset;
private BufferedReader reader;
private BigInteger readCharacters;
private BigInteger mark;
private boolean reopenOnReset;
private final int reopenOnResetThreshold;
private final BigInteger reopenOnResetThresholdBI;
/**
* {#link java.io.BufferedReader#readLine()} is implemented to skip the
* {#code '\n'} of an {#code "\r\n"} only with the next read. The same
* behaviour is implemented here.
*/
private boolean skipLf;
private boolean skipLfMark;
public MarkableFileReader(String fileName) throws FileNotFoundException {
this(fileName, null);
}
public MarkableFileReader(String fileName, Charset charset) throws FileNotFoundException {
this(fileName, charset, DEFAULT_REOPEN_ON_RESET_THRESHOLD);
}
public MarkableFileReader(String fileName, Charset charset, int reopenOnResetThreshold)
throws FileNotFoundException {
this(new File(fileName), charset, reopenOnResetThreshold);
}
public MarkableFileReader(File file) throws FileNotFoundException {
this(file, null, DEFAULT_REOPEN_ON_RESET_THRESHOLD);
}
public MarkableFileReader(File file, Charset charset, int reopenOnResetThreshold) throws FileNotFoundException {
super();
this.file = file;
this.charset = charset;
this.mark = null;
this.skipLfMark = false;
this.reopenOnReset = false;
this.reopenOnResetThreshold = Math.max(0, reopenOnResetThreshold);
this.reopenOnResetThresholdBI = BigInteger.valueOf(this.reopenOnResetThreshold);
initReader();
}
private void initReader() throws FileNotFoundException {
final FileInputStream fileInputStream = new FileInputStream(file);
final InputStreamReader inputStreamReader = (charset == null) ?
new InputStreamReader(fileInputStream) :
new InputStreamReader(fileInputStream, charset);
reader = new BufferedReader(inputStreamReader);
this.readCharacters = BigInteger.ZERO;
this.reopenOnReset = true;
this.skipLf = false;
}
private void incrementReadCharacters() {
this.readCharacters = this.readCharacters.add(BigInteger.ONE);
}
private void incrementReadCharacters(final long characters) {
if(characters != -1) {
this.readCharacters = this.readCharacters.add(BigInteger.valueOf(characters));
}
}
#Override
public int read() throws IOException {
synchronized (lock) {
final int read = reader.read();
if (read != -1) {
incrementReadCharacters();
}
if (skipLf && read == '\n') {
skipLf = false;
return read();
}
return read;
}
}
#Override
public int read(char[] cbuf, int off, int len) throws IOException {
synchronized (lock) {
if ((off < 0) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
if(skipLf) {
int firstChar = read();
if (firstChar == -1) {
return 0;
}
cbuf[off] = (char) firstChar;
if (len > 1) {
final int read = reader.read(cbuf, off + 1, len - 1);
incrementReadCharacters(read);
return read + 1;
} else {
return 1;
}
} else {
final int read = reader.read(cbuf, off, len);
incrementReadCharacters(read);
return read;
}
}
}
/**
* Reads a line of text. A line is considered to be terminated by any one
* of a line feed ('\n'), a carriage return ('\r'), or a carriage return
* followed immediately by a linefeed.
* <p>Note: this is not directly proxied to
* {#link java.io.BufferedReader#readLine()} as we need to know how many
* characters compose the line-ending for {#link #getReadCharacters()} to
* return correct numbers</p>
*
* #return A String containing the contents of the line, not including
* any line-termination characters, or null if the end of the
* stream has been reached
* #throws IOException
* If an I/O error occurs
* #see java.nio.file.Files#readAllLines(java.nio.file.Path, java.nio.charset.Charset)
* #see java.io.BufferedReader#readLine()
*/
public String readLine() throws IOException {
synchronized (lock) {
final CharArrayWriter charArrayWriter = new CharArrayWriter(EXPECTED_LINE_LENGTH);
int lastRead = read();
if(lastRead == -1) {
return null;
}
while (lastRead != -1 && lastRead != '\r' && lastRead != '\n') {
charArrayWriter.write(lastRead);
lastRead = read();
}
if(lastRead == '\r') {
skipLf = true;
}
return charArrayWriter.toString();
}
}
#Override
public long skip(long n) throws IOException {
if (n < 0L) {
throw new IllegalArgumentException("skip value is negative");
}
if(n == 0L) {
return 0L;
}
synchronized (lock) {
if(skipLf) {
int read = read();
if (read == -1) {
return 0;
}
final long skip = reader.skip(n - 1);
incrementReadCharacters(skip);
return skip + 1;
} else {
final long skip = reader.skip(n);
incrementReadCharacters(skip);
return skip;
}
}
}
#Override
public boolean ready() throws IOException {
synchronized (lock) {
return reader.ready();
}
}
#Override
public boolean markSupported() {
return true;
}
#Override
public void mark(int readAheadLimit) throws IOException {
if(readAheadLimit < 0) {
throw new IllegalArgumentException("readAheadLimit needs to be 0 or greater");
}
synchronized (lock) {
mark = readCharacters;
skipLfMark = skipLf;
reopenOnReset = false;
if (reader.markSupported()) {
if (readAheadLimit >= reopenOnResetThreshold) {
reader.mark(reopenOnResetThreshold);
} else {
reader.mark(readAheadLimit);
}
}
}
}
#Override
public void reset() throws IOException {
synchronized (lock) {
if (mark == null) {
throw new IOException("call mark() first");
}
final BigInteger readSinceMark = readCharacters.subtract(mark);
if (reopenOnReset ||
readSinceMark.compareTo(reopenOnResetThresholdBI) >= 0 ||
!reader.markSupported()) {
if (!reopenAt(mark)) {
throw new IOException("reopening at position failed");
}
} else {
reader.reset();
readCharacters = mark;
}
skipLf = skipLfMark;
}
}
#Override
public void close() throws IOException {
synchronized (lock) {
reader.close();
}
}
public BigInteger getReadCharacters() {
synchronized (lock) {
return readCharacters;
}
}
public boolean reopenAt(final BigInteger position) throws IOException {
synchronized (lock) {
if (reader != null) {
reader.close();
}
initReader();
BigInteger skip = skip(position);
return skip.equals(position);
}
}
public BigInteger skip(final BigInteger n) throws IOException {
synchronized (lock) {
BigInteger remaining = n;
while (remaining.compareTo(BigInteger.ZERO) > 0) {
long skip = skip(remaining.min(LONG_MAX_VALUE).longValue());
remaining = remaining.subtract(BigInteger.valueOf(skip));
if (skip < 1) {
break;
}
}
return n.subtract(remaining);
}
}
}

large but not as large as file
This is the problem. Make it as large, or larger. You can't reset further back than the mark quantum.
But you shouldn't have to re-read files at all, this is poor design and poor programming. Compilers can compile programs by only reading source files once, and compilation is a lot more complex than any process you have to carry out.

Related

Java opencsv library: remove quotations from empty values(null values)

I use this library for exporting to CSV file
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.3</version>
</dependency>
I created Builder:
writer = new StatefulBeanToCsvBuilder<T>(printWriter)
.withQuotechar(CSVWriter.DEFAULT_QUOTE_CHARACTER)
.withSeparator(CSVWriter.DEFAULT_SEPARATOR)
.withOrderedResults(false)
.withMappingStrategy(mappingStrategy)
.build();
It Is my POJO:
#Data
public class ReportCsvDto {
#CsvBindByName(column = "NAME")
#CsvBindByPosition(position = 0)
private String name;
#CsvBindByName(column = "ID")
#CsvBindByPosition(position = 1)
private String id;
#CsvBindByName(column = "GENDER")
#CsvBindByPosition(position = 3)
private String gender;
}
How can I remove quotations from empty values?
I have this: "Bill","","male"
I want this: "Bill",,"male"
I want to remove quotations only from empty values
I have looked through the code of opencsv library. And most simple decision which I can come up with now it is just override transmuteBean method in MappingStrategy and passing this new stategy to the builder. For example for ColumnPositionMappingStrategy:
public class CustomColumnPositionMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {
#Override
public String[] transmuteBean(T bean) throws CsvFieldAssignmentException, CsvChainedException {
int numColumns = headerIndex.findMaxIndex()+1;
BeanField<T, Integer> firstBeanField, subsequentBeanField;
Integer firstIndex, subsequentIndex;
List<String> contents = new ArrayList<>(Math.max(numColumns, 0));
// Create a map of types to instances of subordinate beans
Map<Class<?>, Object> instanceMap;
try {
instanceMap = indexBean(bean);
}
catch(IllegalAccessException | InvocationTargetException e) {
// Our testing indicates these exceptions probably can't be thrown,
// but they're declared, so we have to deal with them. It's an
// alibi catch block.
CsvBeanIntrospectionException csve = new CsvBeanIntrospectionException(
ResourceBundle.getBundle(
ICSVParser.DEFAULT_BUNDLE_NAME, errorLocale)
.getString("error.introspecting.beans"));
csve.initCause(e);
throw csve;
}
CsvChainedException chainedException = null;
for(int i = 0; i < numColumns;) {
// Determine the first value
firstBeanField = findField(i);
firstIndex = chooseMultivaluedFieldIndexFromHeaderIndex(i);
String[] fields = ArrayUtils.EMPTY_STRING_ARRAY;
if(firstBeanField != null) {
try {
fields = firstBeanField.write(instanceMap.get(firstBeanField.getType()), firstIndex);
}
catch(CsvDataTypeMismatchException | CsvRequiredFieldEmptyException e) {
if(chainedException != null) {
chainedException.add(e);
}
else {
chainedException = new CsvChainedException(e);
}
}
}
if(fields.length == 0) {
// Write the only value
contents.add(null);
i++; // Advance the index
}
else {
// Multiple values. Write the first.
contents.add(fields[0]);
// Now write the rest.
// We must make certain that we don't write more fields
// than we have columns of the correct type to cover them.
int j = 1;
int displacedIndex = i+j;
subsequentBeanField = findField(displacedIndex);
subsequentIndex = chooseMultivaluedFieldIndexFromHeaderIndex(displacedIndex);
while(j < fields.length
&& displacedIndex < numColumns
&& Objects.equals(firstBeanField, subsequentBeanField)
&& Objects.equals(firstIndex, subsequentIndex)) {
// This field still has a header, so add it
contents.add(fields[j]);
// Prepare for the next loop through
displacedIndex = i + (++j);
subsequentBeanField = findField(displacedIndex);
subsequentIndex = chooseMultivaluedFieldIndexFromHeaderIndex(displacedIndex);
}
i = displacedIndex; // Advance the index
// And here's where we fill in any fields that are missing to
// cover the number of columns of the same type
if(i < numColumns) {
subsequentBeanField = findField(i);
subsequentIndex = chooseMultivaluedFieldIndexFromHeaderIndex(i);
while(Objects.equals(firstBeanField, subsequentBeanField)
&& Objects.equals(firstIndex, subsequentIndex)
&& i < numColumns) {
contents.add(null);
subsequentBeanField = findField(++i);
subsequentIndex = chooseMultivaluedFieldIndexFromHeaderIndex(i);
}
}
}
}
// If there were exceptions, throw them
if(chainedException != null) {
if (chainedException.hasOnlyOneException()) {
throw chainedException.getFirstException();
}
throw chainedException;
}
return contents.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
}
}
And for your example it will produce the following output:
"Bill",,"male"
This overridden method is a simple copy of the original method. But instead of writing empty string on null value it writes null value. And CSVWriter.writeNext method then skips the output of the quotes for null value. This decision can be extended to handle blank lines in the original data too.
As an option you can implement MappingStrategy entirely of course. But I think this is not what you need.
Or you can just implement ICSVWriter for your case or redefine writeNext method for existing subclass. And then you need to pass this CSVWriter to builder. For example CSVWriter.writeNext:
public class CustomCSVWriter extends CSVWriter {
public CustomCSVWriter(Writer writer) {
super(writer);
}
public CustomCSVWriter(Writer writer, char separator, char quotechar, char escapechar, String lineEnd) {
super(writer, separator, quotechar, escapechar, lineEnd);
}
#Override
protected void writeNext(String[] nextLine, boolean applyQuotesToAll, Appendable appendable) throws IOException {
if (nextLine == null) {
return;
}
for (int i = 0; i < nextLine.length; i++) {
if (i != 0) {
appendable.append(separator);
}
String nextElement = nextLine[i];
if (StringUtils.isEmpty(nextElement)) {
continue;
}
Boolean stringContainsSpecialCharacters = stringContainsSpecialCharacters(nextElement);
appendQuoteCharacterIfNeeded(applyQuotesToAll, appendable, stringContainsSpecialCharacters);
if (stringContainsSpecialCharacters) {
processLine(nextElement, appendable);
} else {
appendable.append(nextElement);
}
appendQuoteCharacterIfNeeded(applyQuotesToAll, appendable, stringContainsSpecialCharacters);
}
appendable.append(lineEnd);
writer.write(appendable.toString());
}
private void appendQuoteCharacterIfNeeded(boolean applyQuotesToAll, Appendable appendable, Boolean stringContainsSpecialCharacters) throws IOException {
if ((applyQuotesToAll || stringContainsSpecialCharacters) && quotechar != NO_QUOTE_CHARACTER) {
appendable.append(quotechar);
}
}
}
Overridden method is a simple copy of the original method again. But it skips processing of empty strings (StringUtils.isEmpty(nextElement) check instead of checking for null).
And, of course, you can redefine this behavior in the following way:
public class CustomCSVWriter extends CSVWriter {
public CustomCSVWriter(Writer writer) {
super(writer);
}
public CustomCSVWriter(Writer writer, char separator, char quotechar, char escapechar, String lineEnd) {
super(writer, separator, quotechar, escapechar, lineEnd);
}
#Override
protected void writeNext(String[] nextLine, boolean applyQuotesToAll, Appendable appendable) throws IOException {
if (nextLine != null) {
for (int i = 0; i < nextLine.length; i++) {
if (StringUtils.isEmpty(nextLine[i])) {
nextLine[i] = null;
}
}
}
super.writeNext(nextLine, applyQuotesToAll, appendable);
}
}
Here empty strings are simply replaced with null values. And for me, this method would be more preferable if you do not need to separate empty strings and null values from the original data. Otherwise, the first option (with redefining MappingStrategy) is the only one possible.

How can I continue permutation/combination where I stopped the program?

It's my second time asking here and straight to the point. I can't seem to find a solution and I know it's not impossible. I wrote a java program that can generate a set of combination of any length, when I stop the program I don't want to start from the beginning how can I pick up from where I stopped?
Thanks.
Example (for length 3):
If I start from aaa ==> 9zI and I stop the program here, I don't want to start from aaa all over but start from 9zI and continue to 999. I just want to continue from where I left off.
public class Main {
public static void main(String[] args) {
S_Permutation sp = new S_Permutation();
String text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
FileClass.fileExist("new.txt", true);
System.out.println("");
sp.permutation(text, "", 7, "sha256.txt","Kaaaaaa");
}
}
=====================================================================
public class S_Permutation {
private List<String> permutation;
public S_Permutation() {
permutation = new ArrayList<>();
}
public boolean saveThis(String words, char a, int limit) {
int count = 0;
limit++;
for (char character : words.toCharArray()) {
if (count == limit) {
return false;
}
if (character == a) {
count++;
} else {
count = 0;
}
}
return count < limit;
}
private int counter = 0;
private boolean seen = false;
public void permutation(String str, String prefix, int lengthOfPermutationString, String filename, String startPoint) {
if (prefix.equalsIgnoreCase(startPoint))
{
seen = true;
}
if (counter == 0) {
if (startPoint.length() != lengthOfPermutationString) {
for (int i = startPoint.length(); i < lengthOfPermutationString; i++) {
startPoint += str.charAt(0);
}
}
counter = -45;
}
if (prefix.length() == lengthOfPermutationString) {
boolean savethis = true;
for (int i = 0; i < prefix.length(); i++) {
savethis = this.saveThis(prefix, prefix.charAt(i), 13);
if (!savethis) {
break;
}
}
if (savethis && seen) {
System.out.println(prefix);
//permutation.add(prefix);
}
} else {
for (int i = 0; i < str.length(); i++) {
if (permutation.size() == 1000) {
FileClass.WriteFile("new.txt", permutation);
permutation.clear();
}
permutation(str, prefix + str.charAt(i), lengthOfPermutationString, filename, startPoint);
}
FileClass.WriteFile("new.txt", permutation);
permutation.clear();
}
}
}
=========================================================================
public class FileClass {
public static boolean WriteFile(String filename, List<String> doc) {
try {
if (!filename.contains(".txt")) {
filename += ".txt";
}
RandomAccessFile raf = new RandomAccessFile(filename, "rw");
String writer = "";
writer = doc.stream().map((string) -> string + "\n").reduce(writer, String::concat);
raf.seek(raf.length());
raf.writeBytes(writer);
raf.close();
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println("Error");
new Scanner(System.in).nextLine();
return false;
}
return true;
}
static RandomAccessFile raf;
public static boolean fileExist(String filename, boolean delete){
File file = new File(filename);
if (file.exists() && delete)
{
return file.delete();
}
return file.exists();
}
public static void WriteFile(String filename, String text) {
try {
if (!filename.contains(".txt")) {
filename += ".txt";
}
raf = new RandomAccessFile(filename, "rw");
long length = raf.length();
raf.setLength(length + 1);
raf.seek(raf.length());
raf.writeBytes(text + "\n");
} catch (Exception e) {
}
}
private static void write(List<String> records, Writer writer) throws IOException {
for (String record : records) {
writer.write(record);
}
writer.flush();
writer.close();
}
public static void stringWriter(List<String> records, String filename) {
try {
File file = new File(filename);
FileWriter writer = new FileWriter(file, true);
write(records, writer);
} catch (Exception ex) {
System.out.println(ex.getMessage());
new Scanner(System.in).nextLine();
}
}
public static boolean CloseFile() {
try {
raf.close();
return true;
} catch (Exception e) {
return false;
}
}
}
In order to add a "Resume" mechanism, you need to make your program idempotent. One way to do it, is instead of saving the permutations - save to file the parameters that are sent to permutation on each iteration:
now each time that the program starts, it will check what were the last parameters that permutation was called with (the last line in the file), and start from there (when the program starts on the first time, nothing will be written in the file - so it will start from the beginning).
After that the recursion finished, we can call another method that will go over the lines of the file, and read only the permutations (ignoring the other parameters) and write them into a cleaner "final_result.txt" file.
Needless to say that this implementation is more costly (all the additional reads and write from disc) but that's the tradeoff for having it support "resume" operation.
To save/restore process in the middle of its work, you need something we can call a "state" and implement generating combinations in iterative way.
In my implementation the "state" is pos object (I assume set and k will not change on "resume").
My implementation of the problem would be following:
public class RepeatComb {
private int[] pos;
private String set;
public RepeatComb(String set, int k) {
this.set = set;
pos = new int[k];
}
public int[] getState() {return Arrays.copyOf(pos, pos.length);}
public void resume(int[] a) {pos = Arrays.copyOf(a,a.length);}
public boolean next() {
int i = pos.length-1;
for (int maxpos = set.length()-1; pos[i] >= maxpos; ) {
if (i==0) return false;
--i;
}
++pos[i];
while (++i < pos.length) pos[i]=0;
return true;
}
public String getCur() {
StringBuilder s = new StringBuilder(pos.length);
for (int i=0; i < pos.length; ++i)
s.append(set.charAt(pos[i]));
return s.toString();
}
public static void main(String[] args) {
int[] state;
String text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
RepeatComb comb = new RepeatComb(text, 3);
int stop = 10; //break after 10
do {
if (stop-- == 0) break;
System.out.println(comb.getCur());
} while (comb.next());
//save state
state = comb.getState();
System.out.println("---------");
//resume (with the same args: text,3)
stop = 10; //break after 10
comb = new RepeatComb(text, 3);
comb.resume(state); // resume here
do {
if (stop-- == 0) break;
System.out.println(comb.getCur());
} while (comb.next());
}
}
Update: I've added functions for getting state and resuming from it
and example of use. state array can be saved in file, then restored.

Java File Input - NullPointerException

My code is as follows:
package examen2;
import java.io.*;
import java.util.*;
public class Examen2 {
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("dataIn.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
TreeSet<Punct> set = new TreeSet();
String line;
//problem in the while statement
while (((line = br.readLine()).length() != 0)) {
String[] splited = line.split("([^0-9\\n\\r\\-][^0-9\\n\\r\\-]*)");
int[] number = new int[splited.length];
for (int i=0, j=0; i<splited.length; i++) {
number[j] = Integer.parseInt(splited[i]);
j++;
}
set.add(new Punct(number[0], number[1]));
Iterator it = set.iterator();
while (it.hasNext()) {
System.out.print(it.next());
}
System.out.println();
}
br.close();
br = null;
fis = null;
}
static class Punct implements Comparable {
int x;
int y;
Punct() {
x = 0;
y = 0;
}
Punct(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public String toString() {
return "(" + this.x + ":" + this.y + ")";
}
#Override
public boolean equals(Object o) {
try {
Punct other = (Punct)o;
return (this.x==other.x && this.y==other.y);
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return false;
}
#Override
public int compareTo(Object t) {
Punct other = (Punct)t;
if (this.x == other.x && this.y == other.y) {
return 0;
} else if (Math.sqrt(Math.pow(this.x, 2)+Math.pow(this.y, 2))-Math.sqrt(Math.pow(other.x, 2)+Math.pow(other.y, 2))>0) {
return 1;
} else {
return -1;
}
}
#Override
public int hashCode() {
return super.hashCode(); //To change body of generated methods, choose Tools | Templates.
}
#Override
protected void finalize() throws Throwable {
super.finalize(); //To change body of generated methods, choose Tools | Templates.
}
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); //To change body of generated methods, choose Tools | Templates.
}
}
}
dataIn.txt content:
1 2
3 assfas 4
5 asfl;a 8
1 1
3 4
And it writes out this to the console:
(1:2)
(1:2)(3:4)
(1:2)(3:4)(5:8)
(1:1)(1:2)(3:4)(5:8)
(1:1)(1:2)(3:4)(5:8)
Exception in thread "main" java.lang.NullPointerException
at examen2.Examen2.main(Examen2.java:15)
Java Result: 1 BUILD SUCCESSFUL (total time: 0 seconds)
This is an example for what kind of problems will be at the exam tomorrow.
I have to read the pair of numbers from every row of the input file. I think the problem is not with the regex, but with the interpretation of the result, but I couldn't find the solution.
Where did you pick up this line of code?
while (((line = br.readLine()).length() != 0)) {
It's not good as you'll eventually be calling length() on a null object.
Instead check that line isn't null, and use that in your while condition.
while((line=br.readLine())!=null) {
//....
}
The NullPointerException comes from this line:
while (((line = br.readLine()).length() != 0)) {
When the BufferedReader's readLine() method reaches the end of the stream, it returns null, not an empty string.
Returns:
A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
Try
while ((line = br.readLine() != null) {

Circular ShortBuffer for Audio in Java

I'm implementing an audio track class and I'm in need of a good circular buffer implementation. I'm using shorts for my audio samples, so I would prefer to use a ShortBuffer class for the actual buffer. This track will need to be thread-safe but I can guarantee that only one thread will read and another will write on the track.
My current implementation looks like this (it doesn't handle wrapping).
public class Track {
//sample rate 44100, 2 channels with room for 4 seconds
private volatile ShortBuffer buffer = ShortBuffer.allocate((44100 * 2) * 4);
//keep count of the samples in the buffer
private AtomicInteger count = new AtomicInteger(0);
private ReentrantLock lock = new ReentrantLock(true);
private int readPosition = 0;
public int getSampleCount() {
int i = count.get();
return i > 0 ? i / 2 : 0;
}
public short[] getSamples(int sampleCount) {
short[] samples = new short[sampleCount];
try {
lock.tryLock(10, TimeUnit.MILLISECONDS);
int writePosition = buffer.position();
buffer.position(readPosition);
buffer.get(samples);
//set new read position
readPosition = buffer.position();
// set back to write position
buffer.position(writePosition);
count.addAndGet(-sampleCount);
} catch (InterruptedException e) {
System.err.println("Exception getting samples" + e);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
return samples;
}
public void pushSamples(short[] samples) {
try {
lock.tryLock(10, TimeUnit.MILLISECONDS);
buffer.put(samples);
count.addAndGet(samples.length);
} catch (InterruptedException e) {
System.err.println("Exception getting samples" + e);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
Here's the solution that I have come up with http://pastebin.com/2St01Wzf I decided it was easier to use a head and tail property with a short array, instead of just the read position with a ShortBuffer. I also took an idea from the Java collections classes to detect when the buffer is full. Here is the source, just in case the pastebin disappears:
public class Track {
private static Logger log = LoggerFactory.getLogger(Track.class);
private final long id = System.nanoTime();
// number of channels
private int channelCount;
// maximum seconds to buffer
private int bufferedSeconds = 5;
private AtomicInteger count = new AtomicInteger(0);
private ReentrantLock lock;
private volatile short[] buffer;
private int capacity = 0;
private int head = 0;
private int tail = 0;
public Track(int samplingRate, int channelCount) {
// set the number of channels
this.channelCount = channelCount;
// size the buffer
capacity = (samplingRate * channelCount) * bufferedSeconds;
buffer = new short[capacity];
// use a "fair" lock
lock = new ReentrantLock(true);
}
/**
* Returns the number of samples currently in the buffer.
*
* #return
*/
public int getSamplesCount() {
int i = count.get();
return i > 0 ? i / channelCount : 0;
}
/**
* Removes and returns the next sample in the buffer.
*
* #return single sample or null if a buffer underflow occurs
*/
public Short remove() {
Short sample = null;
if (count.get() > 0) {
// decrement sample counter
count.addAndGet(-1);
// reposition the head
head = (head + 1) % capacity;
// get the sample at the head
sample = buffer[head];
} else {
log.debug("Buffer underflow");
}
return sample;
}
/**
* Adds a sample to the buffer.
*
* #param sample
* #return true if added successfully and false otherwise
*/
public boolean add(short sample) {
boolean result = false;
if ((count.get() + 1) < capacity) {
// increment sample counter
count.addAndGet(1);
// reposition the tail
tail = (tail + 1) % capacity;
// add the sample to the tail
buffer[tail] = sample;
// added!
result = true;
} else {
log.debug("Buffer overflow");
}
return result;
}
/**
* Offers the samples for addition to the buffer, if there is enough capacity to
* contain them they will be added.
*
* #param samples
* #return true if the samples can be added and false otherwise
*/
public boolean offer(short[] samples) {
boolean result = false;
if ((count.get() + samples.length) <= capacity) {
pushSamples(samples);
result = true;
}
return result;
}
/**
* Adds an array of samples to the buffer.
*
* #param samples
*/
public void pushSamples(short[] samples) {
log.trace("[{}] pushSamples - count: {}", id, samples.length);
try {
lock.tryLock(10, TimeUnit.MILLISECONDS);
for (short sample : samples) {
log.trace("Position at write: {}", tail);
if (!add(sample)) {
log.warn("Sample could not be added");
break;
}
}
} catch (InterruptedException e) {
log.warn("Exception getting samples", e);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
/**
* Returns a single from the buffer.
*
* #return
*/
public Short popSample(int channel) {
log.trace("[{}] popSample - channel: {}", id, channel);
Short sample = null;
if (channel < channelCount) {
log.trace("Position at read: {}", head);
try {
lock.tryLock(10, TimeUnit.MILLISECONDS);
sample = remove();
} catch (InterruptedException e) {
log.warn("Exception getting sample", e);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
return sample;
}
}

Wrapping BSD select() with JNA

I need to wrap a BSD-like C socket API to Java with JNA. It has basically the same functions as standard BSD socket API.
Wrapping select() is problematic because of the fd_set-structure required in its arguments and the FD_* masking functions (macros) that are needed to handle fd_sets. I tried to crawl through the header files (e.g. sys/select.h in Ubuntu 8.04) but the definitions are not so straightforward. Especially I found it difficult to find the implementation of FD_*-macros, which is needed when wrapping them with JNA's InvocationMapper.
Note: I'm not trying to wrap the standard TCP or unix-socket API, but a custom one. Thus built-in sockets in Java do not fit the bill.
Especially I found it difficult to find the implementation of FD_*-macros, which is needed when wrapping them with JNA's InvocationMapper.
The C pre-processor cpp is useful to find out how macros are expanded. Write a dummy program that uses the relevant macros (it should be lexically correct, but needn't compile), run it through cpp and watch what happens.
I use a byte array for the fd_set structure and some arithmetic to find the right byte position within the array:
private static final int FD_SETSIZE = 1024;
private static final boolean isBigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
private static interface Libc extends Library {
int select (int nfds, byte[] readfds, byte[] writefds, byte[] errfds, TimeVal timeout);
//...
}
private static class FdSet {
byte[] a;
FdSet() {
a = new byte[FD_SETSIZE / 8]; }
void set (int fd) {
a[getBytePos(fd)] |= getBitMask(fd); }
boolean isSet (int fd) {
return (a[getBytePos(fd)] & getBitMask(fd)) != 0; }
private static int getBytePos (int fd) {
if (fd < 0 || fd >= LibcDefs.FD_SETSIZE) {
throw new RuntimeException("File handle out of range for fd_set."); }
if (isBigEndian) {
return (fd / 8 / Native.LONG_SIZE + 1) * Native.LONG_SIZE - 1 -
fd / 8 % Native.LONG_SIZE; }
else {
return fd / 8; }}
private static int getBitMask (int fd) {
return 1 << (fd % 8); }}
private static class TimeVal extends Structure {
public NativeLong tv_sec;
public NativeLong tv_usec;
TimeVal (int ms) {
set(ms); }
void set (int ms) {
tv_sec.setValue(ms / 1000);
tv_usec.setValue(ms % 1000 * 1000); }
#Override protected List<?> getFieldOrder() {
return Arrays.asList("tv_sec", "tv_usec"); }}
public boolean waitInputReady (int timeoutMs) throws IOException {
TimeVal timeVal = (timeoutMs < 0) ? null : new TimeVal(timeoutMs);
FdSet rxSet = new FdSet();
FdSet errorSet = new FdSet();
rxSet.set(fileHandle);
errorSet.set(fileHandle);
int rc = libc.select(fileHandle + 1, rxSet.a, null, errorSet.a, timeVal);
checkSelectErrors(rc, errorSet);
if (rc == 0) {
return false; }
if (!rxSet.isSet(fileHandle)) {
throw new RuntimeException("rxSet bit is not set after select()."); }
return true; }
public boolean waitOutputReady (int timeoutMs) throws IOException {
TimeVal timeVal = (timeoutMs < 0) ? null : new TimeVal(timeoutMs);
FdSet txSet = new FdSet();
FdSet errorSet = new FdSet();
txSet.set(fileHandle);
errorSet.set(fileHandle);
int rc = libc.select(fileHandle + 1, null, txSet.a, errorSet.a, timeVal);
checkSelectErrors(rc, errorSet);
if (rc == 0) {
return false; }
if (!txSet.isSet(fileHandle)) {
throw new RuntimeException("txSet bit is not set after select()."); }
return true; }
private void checkSelectErrors (int rc, FdSet errorSet) throws IOException {
if (rc == -1) {
throw new IOException("Error in select(), errno=" + Native.getLastError() + "."); }
boolean error = errorSet.isSet(fileHandle);
if (!(rc == 0 && !error || rc == 1 || rc == 2 && error)) {
throw new RuntimeException("Invalid return code received from select(), rc=" + rc + ", error=" + error + "."); }
if (error) {
throw new IOException("Channel error state detected"); }}

Categories