+
+ Read files with asText(), asBytes() and asLines()
+
+
+
+
+
+
+ Added
+ asBytes(),
+
+ asText(encoding),
+ and
+ asLines(encoding) methods into
+ FileObject
+ to simplify reading of its content.
+
+
+
+
Possibility to add FileChangeListeners on File (even not existing)
diff -r bd8aef593115 openide.filesystems/nbproject/project.properties
--- a/openide.filesystems/nbproject/project.properties Thu Jan 29 17:56:55 2009 +0100
+++ b/openide.filesystems/nbproject/project.properties Wed Feb 04 12:50:07 2009 +0100
@@ -44,4 +44,4 @@
javadoc.main.page=org/openide/filesystems/doc-files/api.html
javadoc.arch=${basedir}/arch.xml
javadoc.apichanges=${basedir}/apichanges.xml
-spec.version.base=7.20.0
+spec.version.base=7.21.0
diff -r bd8aef593115 openide.filesystems/src/org/openide/filesystems/FileObject.java
--- a/openide.filesystems/src/org/openide/filesystems/FileObject.java Thu Jan 29 17:56:55 2009 +0100
+++ b/openide.filesystems/src/org/openide/filesystems/FileObject.java Wed Feb 04 12:50:07 2009 +0100
@@ -49,13 +49,17 @@
import java.io.OutputStream;
import java.io.Serializable;
import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.AbstractSequentialList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.ListIterator;
import java.util.StringTokenizer;
import org.openide.util.Enumerations;
import org.openide.util.NbBundle;
@@ -161,6 +165,7 @@
*
* @return some representation of this file object
*/
+ @Override
public String toString() {
String cname = getClass().getName();
String cnameShort = cname.substring(cname.lastIndexOf('.') + 1);
@@ -502,6 +507,121 @@
* rather than a regular file or is invalid
*/
public abstract InputStream getInputStream() throws FileNotFoundException;
+
+ /** Reads the full content of the file object and returns it as array of
+ * bytes.
+ * @return array of bytes
+ * @exception IOException in case the content cannot be fully read
+ * @since 7.21
+ */
+ public byte[] asBytes() throws IOException {
+ long len = getSize();
+ if (len > Integer.MAX_VALUE) {
+ throw new IOException("Too big file " + getPath()); // NOI18N
+ }
+ InputStream is = getInputStream();
+ try {
+ byte[] arr = new byte[(int)len];
+ int pos = 0;
+ while (pos < arr.length) {
+ int read = is.read(arr, pos, arr.length - pos);
+ if (read == -1) {
+ break;
+ }
+ pos += read;
+ }
+ if (pos != arr.length) {
+ throw new IOException("Just " + pos + " bytes read from " + getPath()); // NOI18N
+ }
+ return arr;
+ } finally {
+ is.close();
+ }
+ }
+
+ /** Reads the full content of the file object and returns it as string.
+ * @param encoding the encoding to use
+ * @return string representing the content of the file
+ * @exception IOException in case the content cannot be fully read
+ * @since 7.21
+ */
+ public String asText(String encoding) throws IOException {
+ return new String(asBytes(), encoding);
+ }
+
+ /** Reads the full content of the file object and returns it as string.
+ * This is similar to calling {@link #asText(java.lang.String)} with
+ * default system encoding.
+ *
+ * @return string representing the content of the file
+ * @exception IOException in case the content cannot be fully read
+ * @since 7.21
+ */
+ public String asText() throws IOException {
+ return asText(Charset.defaultCharset().name());
+ }
+
+ /** Reads the full content of the file line by line with default
+ * system encoding. Typical usage is
+ * in for
loops:
+ *
+ * for (String line : fo.asLines()) {
+ * // do something
+ * }
+ *
+ *
+ * The list is optimized for iterating line by line, other operations,
+ * like accessing all the lines or counting the number of its lines may
+ * be suboptimal.
+ *
+ * @return list of strings representing the content of the file
+ * @exception IOException in case the content cannot be fully read
+ * @since 7.21
+ */
+ public List asLines() throws IOException {
+ return asLines(Charset.defaultCharset().name());
+ }
+
+ /** Reads the full content of the file line by line. Typical usage is
+ * in for
loops:
+ *
+ * for (String line : fo.asLines("UTF-8")) {
+ * // do something
+ * }
+ *
+ *
+ * The list is optimized for iterating line by line, other operations,
+ * like accessing all the lines or counting the number of its lines may
+ * be suboptimal.
+ *
+ * @param encoding the encoding to use
+ * @return list of strings representing the content of the file
+ * @exception IOException in case the content cannot be fully read
+ * @since 7.21
+ */
+ public List asLines(final String encoding) throws IOException {
+ return new AbstractSequentialList() {
+ final FileObjectLineIterator ready = new FileObjectLineIterator(FileObject.this, encoding);
+
+ public synchronized ListIterator listIterator(int position) {
+ FileObjectLineIterator ret = ready.cloneIterator();
+ while (position-- > 0) {
+ ret.next();
+ }
+ return ret;
+ }
+
+ public synchronized int size() {
+ int cnt = 0;
+ Iterator it = listIterator();
+ while (it.hasNext()) {
+ it.next();
+ cnt++;
+ }
+ return cnt;
+ }
+ };
+ }
/** Get output stream.
* @param lock the lock that belongs to this file (obtained by a call to
@@ -951,14 +1071,14 @@
}
if (fs != null && fsList != null) {
for (FileChangeListener fcl : fsList) {
- fs.getFCLSupport().dispatchEvent(fcl, fe, op);
+ FCLSupport.dispatchEvent(fcl, fe, op);
}
}
if (rep != null && repList != null) {
for (FileChangeListener fcl : repList) {
- rep.getFCLSupport().dispatchEvent(fcl, fe, op);
+ FCLSupport.dispatchEvent(fcl, fe, op);
}
}
}
diff -r bd8aef593115 openide.filesystems/src/org/openide/filesystems/FileObjectLineIterator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/openide.filesystems/src/org/openide/filesystems/FileObjectLineIterator.java Wed Feb 04 12:50:07 2009 +0100
@@ -0,0 +1,167 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.openide.filesystems;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+import org.openide.util.Exceptions;
+
+/** Iterator for list of lines.
+ * @author Jaroslav Tulach
+ */
+final class FileObjectLineIterator implements ListIterator {
+ private final FileObject fo;
+ private final String encoding;
+ private byte[] buffer;
+ private BufferedReader reader;
+ private String line;
+ private int index;
+
+ public FileObjectLineIterator(FileObject fo, String encoding) throws IOException {
+ this.fo = fo;
+ this.encoding = encoding;
+ initReader();
+ }
+
+ private FileObjectLineIterator(FileObjectLineIterator orig) {
+ this.fo = orig.fo;
+ this.encoding = orig.encoding;
+ this.buffer = orig.buffer;
+ try {
+ initReader();
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+
+ public synchronized boolean hasNext() {
+ if (line == null) {
+ try {
+ line = reader.readLine();
+ if (line == null) {
+ reader.close();
+ }
+ index++;
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ return line != null;
+ }
+
+ public synchronized String next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ String l = line;
+ line = null;
+ return l;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public synchronized boolean hasPrevious() {
+ return index > 0;
+ }
+
+ public synchronized String previous() {
+ if (index == 0) {
+ throw new NoSuchElementException();
+ }
+ try {
+ int pos = index - 1;
+ initReader();
+ String last = null;
+ while (index <= pos) {
+ last = next();
+ }
+ index--;
+ return last;
+ } catch (IOException ex) {
+ throw (NoSuchElementException)new NoSuchElementException().initCause(ex);
+ }
+ }
+
+ public synchronized int nextIndex() {
+ return index;
+ }
+
+ public synchronized int previousIndex() {
+ return index - 1;
+ }
+
+ public void set(String e) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void add(String e) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ private void initReader() throws UnsupportedEncodingException, IOException {
+ InputStream is;
+ if (fo.getSize() < 64 * 1024) {
+ if (buffer == null) {
+ buffer = fo.asBytes();
+ }
+ is = new ByteArrayInputStream(buffer);
+ } else {
+ is = fo.getInputStream();
+ }
+ this.reader = new BufferedReader(new InputStreamReader(is, encoding));
+ this.index = 0;
+ while (this.index < index) {
+ next();
+ }
+ }
+
+ final FileObjectLineIterator cloneIterator() {
+ return new FileObjectLineIterator(this);
+ }
+}
diff -r bd8aef593115 openide.filesystems/test/unit/src/org/openide/filesystems/FileObjectTestHid.java
--- a/openide.filesystems/test/unit/src/org/openide/filesystems/FileObjectTestHid.java Thu Jan 29 17:56:55 2009 +0100
+++ b/openide.filesystems/test/unit/src/org/openide/filesystems/FileObjectTestHid.java Wed Feb 04 12:50:07 2009 +0100
@@ -82,6 +82,7 @@
super(testName);
}
+ @Override
protected void setUp() throws java.lang.Exception {
MockServices.setServices();
@@ -92,6 +93,7 @@
root = fs.findResource(getResourcePrefix());
}
+ @Override
protected void tearDown() throws Exception {
super.tearDown();
fs = this.testedFS = null;
@@ -118,17 +120,20 @@
class L extends FileChangeAdapter {
public int cnt;
+ @Override
public void fileDataCreated(FileEvent fe) {
cnt++;
}
}
final FileChangeListener noFileDataCreatedListener = new FileChangeAdapter(){
+ @Override
public void fileDataCreated(FileEvent fe) {
fail();
}
};
final FileChangeListener listener1 = new FileChangeAdapter(){
+ @Override
public void fileDataCreated(FileEvent fe) {
try {
fold.getFileSystem().removeFileChangeListener(noFileDataCreatedListener);
@@ -172,11 +177,13 @@
return;
}
final FileChangeListener noFileDataCreatedListener = new FileChangeAdapter(){
+ @Override
public void fileDataCreated(FileEvent fe) {
fail();
}
};
final FileChangeListener listener1 = new FileChangeAdapter(){
+ @Override
public void fileDataCreated(FileEvent fe) {
fold.removeFileChangeListener(noFileDataCreatedListener);
fold.addFileChangeListener(noFileDataCreatedListener);
@@ -1543,6 +1550,7 @@
public static void implOfTestGetFileObjectForSubversion(final FileObject folder, final String childName) throws InterruptedException {
final List l = new ArrayList();
folder.addFileChangeListener(new FileChangeAdapter(){
+ @Override
public void fileFolderCreated(FileEvent fe) {
l.add(fe.getFile());
synchronized(l) {
@@ -1812,6 +1820,120 @@
fsAssert ("After delete should be invalid",!fo1.isValid());
}
+ public void testAsBytesAndString() throws java.io.FileNotFoundException, IOException {
+ checkSetUp();
+
+ FileObject fo1 = getTestFile1 (root);
+ try {
+ OutputStream os = fo1.getOutputStream();
+ String txt = "Ahoj\nJak\nSe\nMas";
+ os.write(txt.getBytes("UTF-8"));
+ os.close();
+ byte[] arr = fo1.asBytes();
+ assertNotNull("Arrays is read", arr);
+ assertEquals("Right length bytes", txt.length(), arr.length);
+ assertEquals(txt, new String(arr, "UTF-8"));
+ assertEquals(txt, fo1.asText("UTF-8"));
+
+ ArrayList all = new ArrayList();
+ List lines = fo1.asLines("UTF-8");
+ for (String l : lines) {
+ // it is possible to rewrite the content, if the file is small
+ fo1.getOutputStream().close();
+ all.add(l);
+ }
+ assertEquals("Four lines: " + txt, 4, all.size());
+ assertEquals("Computed remain the same as read", all, lines);
+
+ ListIterator it = lines.listIterator(all.size());
+ for (int i = all.size(); i > 0; ) {
+ i--;
+ assertEquals("Right index", i, it.previousIndex());
+ assertEquals("Ith " + i, all.get(i), it.previous());
+ }
+ } catch (IOException iex) {
+ fsAssert ("Expected that FS provides InputStream ",fo1.getSize () == 0);
+ }
+ FileLock lock = null;
+
+ try {
+ lock = fo1.lock ();
+ fo1.delete(lock);
+ } catch (IOException iex) {
+ fsAssert("FileObject shopuld be allowd to be modified.",
+ fs.isReadOnly() || fo1.isReadOnly()) ;
+ return;
+ } finally {
+ if (lock != null) lock.releaseLock();
+ }
+ fsAssert ("After delete should be invalid",!fo1.isValid());
+ }
+ public void testBigFileAndAsString() throws java.io.FileNotFoundException, IOException {
+ checkSetUp();
+
+ FileObject fo1 = getTestFile1 (root);
+ try {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 1000; i++) {
+ sb.append("Hi how are you, boy! ");
+ }
+ sb.append("\n");
+
+ OutputStream os = fo1.getOutputStream();
+ for (int i = 0; i < 10; i++) {
+ os.write(sb.toString().getBytes("UTF-8"));
+ }
+ os.close();
+ if (64 * 1024 > fo1.getSize()) {
+ fail("We need to generate big file: " + fo1.getSize());
+ }
+
+ OutputStream tmp = null;
+ FileLock lock = null;
+ int acquire = 3;
+ List lines = fo1.asLines("UTF-8");
+ LinkedList reverse = new LinkedList();
+ for (int i = lines.size() - 1; i >= 0; i--) {
+ reverse.add(0, lines.get(i));
+ }
+
+ ArrayList all = new ArrayList();
+ for (String l : fo1.asLines("UTF-8")) {
+ int cnt = all.size();
+ if (cnt % 100 == 0 && acquire-- > 0) {
+ try {
+ lock = fo1.lock();
+ tmp = fo1.getOutputStream(lock);
+ tmp.write(0);
+ fail("The input stream is open for big files. cnt = " + cnt);
+ } catch (IOException ex) {
+ // OK
+ } finally {
+ lock.releaseLock();
+ }
+ }
+ all.add(l);
+ }
+ if (tmp != null) {
+ tmp.close();
+ }
+ assertEquals("Some lines: ", 10, all.size());
+ assertEquals("Generated same as read", all, fo1.asLines());
+ assertEquals("Normal and reverse are same", all, reverse);
+ } catch (IOException iex) {
+ fsAssert ("Expected that FS provides InputStream ",fo1.getSize () == 0);
+ }
+
+ try {
+ FileLock lock = fo1.lock ();
+ fo1.delete(lock);
+ } catch (IOException iex) {
+ fsAssert("FileObject shopuld be allowd to be modified.",
+ fs.isReadOnly() || fo1.isReadOnly()) ;
+ return;
+ }
+ fsAssert ("After delete should be invalid",!fo1.isValid());
+ }
/** Test of getOutputStream() method, of class org.openide.filesystems.FileObject. */
public void testGetOutputStream() throws java.io.IOException {