1 /* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 package org.tensorflow.lite.support.common;
17 
18 import android.content.Context;
19 import android.content.res.AssetFileDescriptor;
20 import java.io.BufferedReader;
21 import java.io.FileInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.nio.ByteBuffer;
26 import java.nio.MappedByteBuffer;
27 import java.nio.channels.FileChannel;
28 import java.nio.charset.Charset;
29 import java.util.ArrayList;
30 import java.util.List;
31 import org.checkerframework.checker.nullness.qual.NonNull;
32 
33 /** File I/O utilities. */
34 public class FileUtil {
FileUtil()35   private FileUtil() {}
36 
37   /**
38    * Loads labels from the label file into a list of strings.
39    *
40    * <p>A legal label file is the plain text file whose contents are split into lines, and each line
41    * is an individual value. The file should be in assets of the context.
42    *
43    * @param context The context holds assets.
44    * @param filePath The path of the label file, relative with assets directory.
45    * @return a list of labels.
46    * @throws IOException if error occurs to open or read the file.
47    */
48   @NonNull
loadLabels(@onNull Context context, @NonNull String filePath)49   public static List<String> loadLabels(@NonNull Context context, @NonNull String filePath)
50       throws IOException {
51     return loadLabels(context, filePath, Charset.defaultCharset());
52   }
53 
54   /**
55    * Loads labels from the label file into a list of strings.
56    *
57    * <p>A legal label file is the plain text file whose contents are split into lines, and each line
58    * is an individual value. The empty lines will be ignored. The file should be in assets of the
59    * context.
60    *
61    * @param context The context holds assets.
62    * @param filePath The path of the label file, relative with assets directory.
63    * @param cs {@code Charset} to use when decoding content of label file.
64    * @return a list of labels.
65    * @throws IOException if error occurs to open or read the file.
66    */
67   @NonNull
loadLabels( @onNull Context context, @NonNull String filePath, Charset cs)68   public static List<String> loadLabels(
69       @NonNull Context context, @NonNull String filePath, Charset cs) throws IOException {
70     SupportPreconditions.checkNotNull(context, "Context cannot be null.");
71     SupportPreconditions.checkNotNull(filePath, "File path cannot be null.");
72     try (InputStream inputStream = context.getAssets().open(filePath)) {
73       return loadLabels(inputStream, cs);
74     }
75   }
76 
77   /**
78    * Loads labels from an input stream of an opened label file. See details for label files in
79    * {@link FileUtil#loadLabels(Context, String)}.
80    *
81    * @param inputStream the input stream of an opened label file.
82    * @return a list of labels.
83    * @throws IOException if error occurs to open or read the file.
84    */
85   @NonNull
loadLabels(@onNull InputStream inputStream)86   public static List<String> loadLabels(@NonNull InputStream inputStream) throws IOException {
87     return loadLabels(inputStream, Charset.defaultCharset());
88   }
89 
90   /**
91    * Loads labels from an input stream of an opened label file. See details for label files in
92    * {@link FileUtil#loadLabels(Context, String)}.
93    *
94    * @param inputStream the input stream of an opened label file.
95    * @param cs {@code Charset} to use when decoding content of label file.
96    * @return a list of labels.
97    * @throws IOException if error occurs to open or read the file.
98    */
99   @NonNull
loadLabels(@onNull InputStream inputStream, Charset cs)100   public static List<String> loadLabels(@NonNull InputStream inputStream, Charset cs)
101       throws IOException {
102     List<String> labels = new ArrayList<>();
103     try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, cs))) {
104       String line;
105       while ((line = reader.readLine()) != null) {
106         if (line.trim().length() > 0) {
107           labels.add(line);
108         }
109       }
110       return labels;
111     }
112   }
113 
114   /**
115    * Loads a vocabulary file (a single-column text file) into a list of strings.
116    *
117    * <p>A vocabulary file is a single-column plain text file whose contents are split into lines,
118    * and each line is an individual value. The file should be in assets of the context.
119    *
120    * @param context The context holds assets.
121    * @param filePath The path of the vocabulary file, relative with assets directory.
122    * @return a list of vocabulary words.
123    * @throws IOException if error occurs to open or read the file.
124    */
125   @NonNull
loadSingleColumnTextFile( @onNull Context context, @NonNull String filePath, Charset cs)126   public static List<String> loadSingleColumnTextFile(
127       @NonNull Context context, @NonNull String filePath, Charset cs) throws IOException {
128     return loadLabels(context, filePath, cs);
129   }
130 
131   /**
132    * Loads vocabulary from an input stream of an opened vocabulary file (which is a single-column
133    * text file). See details for vocabulary files in {@link FileUtil#loadVocabularyFile(Context,
134    * String)}.
135    *
136    * @param inputStream the input stream of an opened vocabulary file.
137    * @return a list of vocabulary words.
138    * @throws IOException if error occurs to open or read the file.
139    */
140   @NonNull
loadSingleColumnTextFile(@onNull InputStream inputStream, Charset cs)141   public static List<String> loadSingleColumnTextFile(@NonNull InputStream inputStream, Charset cs)
142       throws IOException {
143     return loadLabels(inputStream, cs);
144   }
145 
146   /**
147    * Loads a file from the asset folder through memory mapping.
148    *
149    * @param context Application context to access assets.
150    * @param filePath Asset path of the file.
151    * @return the loaded memory mapped file.
152    * @throws IOException if an I/O error occurs when loading the tflite model.
153    */
154   @NonNull
loadMappedFile(@onNull Context context, @NonNull String filePath)155   public static MappedByteBuffer loadMappedFile(@NonNull Context context, @NonNull String filePath)
156       throws IOException {
157     SupportPreconditions.checkNotNull(context, "Context should not be null.");
158     SupportPreconditions.checkNotNull(filePath, "File path cannot be null.");
159     try (AssetFileDescriptor fileDescriptor = context.getAssets().openFd(filePath);
160     FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor())) {
161       FileChannel fileChannel = inputStream.getChannel();
162       long startOffset = fileDescriptor.getStartOffset();
163       long declaredLength = fileDescriptor.getDeclaredLength();
164       return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength);
165     }
166   }
167 
168   /**
169    * Loads a binary file from the asset folder.
170    *
171    * @param context Application context to access assets.
172    * @param filePath Asset path of the file.
173    * @return the byte array for the binary file.
174    * @throws IOException if an I/O error occurs when loading file.
175    */
176   @NonNull
loadByteFromFile(@onNull Context context, @NonNull String filePath)177   public static byte[] loadByteFromFile(@NonNull Context context, @NonNull String filePath)
178       throws IOException {
179     ByteBuffer buffer = loadMappedFile(context, filePath);
180     byte[] byteArray = new byte[buffer.remaining()];
181     buffer.get(byteArray);
182     return byteArray;
183   }
184 }
185