【问题标题】:Reading CSV File In Android App在 Android 应用程序中读取 CSV 文件
【发布时间】:2017-08-20 16:57:59
【问题描述】:

我正在开发一个概念验证应用程序,以便我可以在我正在制作的更大应用程序中实现该功能。我对 Java 和 Android Dev 有点陌生,但希望这个问题不会太简单或太复杂。

基本上,我正在尝试从 CSV 文件中读取字符串列表,并使其可用于在应用程序的 Main Activity 上显示列表。

我正在使用一个外部类来读取 CSV 文件。这是课程代码:

CSVFile.java

package com.yourtechwhiz.listdisplay;

import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class CSVFile {
    InputStream inputStream;

    public CSVFile(InputStream inputStream){
        this.inputStream = inputStream;
    }

    public List read(){
        List resultList = new ArrayList();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        try {
            String csvLine;
            while ((csvLine = reader.readLine()) != null) {
                String[] row = csvLine.split(",");
                resultList.add(row);
                Log.d("VariableTag", row[0].toString());
            }
        }
        catch (IOException ex) {
            throw new RuntimeException("Error in reading CSV file: "+ex);
        }
        finally {
            try {
                inputStream.close();
            }
            catch (IOException e) {
                throw new RuntimeException("Error while closing input stream: "+e);
            }
        }
        return resultList;
    }
}

这是我的主要活动代码:

MainActivity.java

package com.yourtechwhiz.listdisplay;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    // Array of strings that's used to display on screen
    String[] mobileArray = {"Android","IPhone","WindowsMobile","Blackberry",
            "WebOS","Ubuntu","Windows7","Max OS X"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        prepArray();

        //Display List on Activity
        ArrayAdapter adapter = new ArrayAdapter<String>(this,
                R.layout.activity_listview, mobileArray);
        ListView listView = (ListView) findViewById(R.id.mobile_list);
        listView.setAdapter(adapter);

    }

    //Get list of strings from CSV ready to use
    private void prepArray() {

        InputStream inputStream = getResources().openRawResource(R.raw.strings);
        CSVFile csvFile = new CSVFile(inputStream);
        List myList = csvFile.read();

        //This is where it has an error
        //Set first array in myList to this new array myArray
        String[] myArray = myList.get(0);

    }

}

我实际上还没有到设置 mobileArray 数组的地步。现在我只是想从 List 对象 myList 中“提取”信息...

有人可以向我解释一下这是怎么做到的吗?也许我只是不完全理解 List 类型。似乎当在 CSVFile 读取方法中返回 resultList 时,它作为由 String 数组对象组成的 List 对象返回。但我似乎无法让它像那样工作。

感谢任何帮助!

最终编辑(工作代码)

private void prepArray() {

        try{
            CSVReader reader = new CSVReader(new InputStreamReader(getResources().openRawResource(R.raw.strings)));//Specify asset file name
            String [] nextLine;
            while ((nextLine = reader.readNext()) != null) {
                // nextLine[] is an array of values from the line
                System.out.println(nextLine[0] + nextLine[1] + "etc...");
                Log.d("VariableTag", nextLine[0]);
            }
        }catch(Exception e){
            e.printStackTrace();
            Toast.makeText(this, "The specified file was not found", Toast.LENGTH_SHORT).show();
        }

    }

编辑

现在我的 prepArray 函数如下所示:

    private void prepArray() {

        try{
            String csvfileString = this.getApplicationInfo().dataDir + File.separatorChar + "strings.csv"
            File csvfile = new File(csvfileString);
            CSVReader reader = new CSVReader(new FileReader("csvfile.getAbsolutePath()"));
            String [] nextLine;
            while ((nextLine = reader.readNext()) != null) {
                // nextLine[] is an array of values from the line
                System.out.println(nextLine[0] + nextLine[1] + "etc...");
            }
        }catch(FileNotFoundException e){
            e.printStackTrace();
            Toast.makeText(this, "The specified file was not found", Toast.LENGTH_SHORT).show();
        }

    }

仍然产生 FileNotFoundException。

编辑 2/3

这是我在实际手机上运行应用程序时生成的日志,其中 strings.csv 位于字符串的子文件夹 (src\main\assets\strings\strings.csv) 中,其中包含您对代码请求的更改:

03/27 17:44:01: Launching app
        $ adb push C:\Users\Roy\AndroidStudioProjects\ListDisplay\app\build\outputs\apk\app-debug.apk /data/local/tmp/com.yourtechwhiz.listdisplay
        $ adb shell pm install -r "/data/local/tmp/com.yourtechwhiz.listdisplay"
        pkg: /data/local/tmp/com.yourtechwhiz.listdisplay
        Success


        $ adb shell am start -n "com.yourtechwhiz.listdisplay/com.yourtechwhiz.listdisplay.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -D
        Connecting to com.yourtechwhiz.listdisplay
        D/HyLog: I : /data/font/config/sfconfig.dat, No such file or directory (2)
        D/HyLog: I : /data/font/config/dfactpre.dat, No such file or directory (2)
        D/HyLog: I : /data/font/config/sfconfig.dat, No such file or directory (2)
        W/ActivityThread: Application com.yourtechwhiz.listdisplay is waiting for the debugger on port 8100...
        I/System.out: Sending WAIT chunk
        I/dalvikvm: Debugger is active
        I/System.out: Debugger has connected
        I/System.out: waiting for debugger to settle...
        Connected to the target VM, address: 'localhost:8609', transport: 'socket'
        I/System.out: waiting for debugger to settle...
        I/System.out: waiting for debugger to settle...
        I/System.out: waiting for debugger to settle...
        I/System.out: waiting for debugger to settle...
        I/System.out: waiting for debugger to settle...
        I/System.out: waiting for debugger to settle...
        I/System.out: waiting for debugger to settle...
        I/System.out: debugger has settled (1498)
        I/dalvikvm: Could not find method android.view.Window$Callback.onProvideKeyboardShortcuts, referenced from method android.support.v7.view.WindowCallbackWrapper.onProvideKeyboardShortcuts
        W/dalvikvm: VFY: unable to resolve interface method 16152: Landroid/view/Window$Callback;.onProvideKeyboardShortcuts (Ljava/util/List;Landroid/view/Menu;I)V
        D/dalvikvm: VFY: replacing opcode 0x72 at 0x0002
        W/dalvikvm: VFY: unable to find class referenced in signature (Landroid/view/SearchEvent;)
        I/dalvikvm: Could not find method android.view.Window$Callback.onSearchRequested, referenced from method android.support.v7.view.WindowCallbackWrapper.onSearchRequested
        W/dalvikvm: VFY: unable to resolve interface method 16154: Landroid/view/Window$Callback;.onSearchRequested (Landroid/view/SearchEvent;)Z
        D/dalvikvm: VFY: replacing opcode 0x72 at 0x0002
        I/dalvikvm: Could not find method android.view.Window$Callback.onWindowStartingActionMode, referenced from method android.support.v7.view.WindowCallbackWrapper.onWindowStartingActionMode
        W/dalvikvm: VFY: unable to resolve interface method 16158: Landroid/view/Window$Callback;.onWindowStartingActionMode (Landroid/view/ActionMode$Callback;I)Landroid/view/ActionMode;
        D/dalvikvm: VFY: replacing opcode 0x72 at 0x0002
        I/dalvikvm: Could not find method android.content.res.TypedArray.getChangingConfigurations, referenced from method android.support.v7.widget.TintTypedArray.getChangingConfigurations
        W/dalvikvm: VFY: unable to resolve virtual method 455: Landroid/content/res/TypedArray;.getChangingConfigurations ()I
        D/dalvikvm: VFY: replacing opcode 0x6e at 0x0002
        I/dalvikvm: Could not find method android.content.res.TypedArray.getType, referenced from method android.support.v7.widget.TintTypedArray.getType
        W/dalvikvm: VFY: unable to resolve virtual method 477: Landroid/content/res/TypedArray;.getType (I)I
        D/dalvikvm: VFY: replacing opcode 0x6e at 0x0008
        I/dalvikvm: Could not find method android.widget.FrameLayout.startActionModeForChild, referenced from method android.support.v7.widget.ActionBarContainer.startActionModeForChild
        W/dalvikvm: VFY: unable to resolve virtual method 16589: Landroid/widget/FrameLayout;.startActionModeForChild (Landroid/view/View;Landroid/view/ActionMode$Callback;I)Landroid/view/ActionMode;
        D/dalvikvm: VFY: replacing opcode 0x6f at 0x0002
        I/dalvikvm: Could not find method android.content.Context.getColorStateList, referenced from method android.support.v7.content.res.AppCompatResources.getColorStateList
        W/dalvikvm: VFY: unable to resolve virtual method 269: Landroid/content/Context;.getColorStateList (I)Landroid/content/res/ColorStateList;
        D/dalvikvm: VFY: replacing opcode 0x6e at 0x0006
        I/dalvikvm: Could not find method android.content.res.Resources.getDrawable, referenced from method android.support.v7.widget.ResourcesWrapper.getDrawable
        W/dalvikvm: VFY: unable to resolve virtual method 418: Landroid/content/res/Resources;.getDrawable (ILandroid/content/res/Resources$Theme;)Landroid/graphics/drawable/Drawable;
        D/dalvikvm: VFY: replacing opcode 0x6e at 0x0002
        I/dalvikvm: Could not find method android.content.res.Resources.getDrawableForDensity, referenced from method android.support.v7.widget.ResourcesWrapper.getDrawableForDensity
        W/dalvikvm: VFY: unable to resolve virtual method 420: Landroid/content/res/Resources;.getDrawableForDensity (IILandroid/content/res/Resources$Theme;)Landroid/graphics/drawable/Drawable;
        D/dalvikvm: VFY: replacing opcode 0x6e at 0x0002
        E/dalvikvm: Could not find class 'android.graphics.drawable.RippleDrawable', referenced from method android.support.v7.widget.AppCompatImageHelper.hasOverlappingRendering
        W/dalvikvm: VFY: unable to resolve instanceof 140 (Landroid/graphics/drawable/RippleDrawable;) in Landroid/support/v7/widget/AppCompatImageHelper;
        D/dalvikvm: VFY: replacing opcode 0x20 at 0x000c
        W/System.err: java.io.FileNotFoundException: /csvfile.getAbsolutePath(): open failed: ENOENT (No such file or directory)
        W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:462)
        W/System.err:     at java.io.FileInputStream.<init>(FileInputStream.java:78)
        W/System.err:     at java.io.FileInputStream.<init>(FileInputStream.java:105)
        W/System.err:     at java.io.FileReader.<init>(FileReader.java:66)
        W/System.err:     at com.yourtechwhiz.listdisplay.MainActivity.prepArray(MainActivity.java:43)
        W/System.err:     at com.yourtechwhiz.listdisplay.MainActivity.onCreate(MainActivity.java:26)
        W/System.err:     at android.app.Activity.performCreate(Activity.java:5287)
        W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
        W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2145)
        W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2231)
        W/System.err:     at android.app.ActivityThread.access$700(ActivityThread.java:139)
        W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1401)
        W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
        W/System.err:     at android.os.Looper.loop(Looper.java:137)
        W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5082)
        W/System.err:     at java.lang.reflect.Method.invokeNative(Native Method)
        W/System.err:     at java.lang.reflect.Method.invoke(Method.java:515)
        W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
        W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:598)
        W/System.err:     at dalvik.system.NativeStart.main(Native Method)
        W/System.err: Caused by: libcore.io.ErrnoException: open failed: ENOENT (No such file or directory)
        W/System.err:     at libcore.io.Posix.open(Native Method)
        W/System.err:     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
        W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:446)
        W/System.err:   ... 19 more
        I/Adreno-EGL: <qeglDrvAPI_eglInitialize:385>: EGL 1.4 QUALCOMM build:  ()
        OpenGL ES Shader Compiler Version: E031.24.00.01
        Build Date: 12/27/13 Fri
        Local Branch: qualcomm_only
        Remote Branch:
        Local Patches:
        Reconstruct Branch:
        D/OpenGLRenderer: Enabling debug mode 0
        D/OpenGLRenderer: GL error from OpenGLRenderer: 0x502
        E/OpenGLRenderer:   GL_INVALID_OPERATION

【问题讨论】:

  • 注意:csvLine.split(",") 不能在 列中正确使用逗号

标签: java android csv


【解决方案1】:

试试OpenCSV - 它会让您的生活更轻松。

首先,将此包添加到您的 gradle 依赖项中,如下所示

implementation 'com.opencsv:opencsv:4.6'

那么你可以这样做

import com.opencsv.CSVReader;
import java.io.IOException;
import java.io.FileReader;


...

try {
    CSVReader reader = new CSVReader(new FileReader("yourfile.csv"));
    String[] nextLine;
    while ((nextLine = reader.readNext()) != null) {
        // nextLine[] is an array of values from the line
        System.out.println(nextLine[0] + nextLine[1] + "etc...");
    }
} catch (IOException e) {

}

CSVReader reader = new CSVReader(new FileReader("yourfile.csv"));
List myEntries = reader.readAll();

评论后编辑

try {
    File csvfile = new File(Environment.getExternalStorageDirectory() + "/csvfile.csv");
    CSVReader reader = new CSVReader(new FileReader(csvfile.getAbsolutePath()));
    String[] nextLine;
    while ((nextLine = reader.readNext()) != null) {
        // nextLine[] is an array of values from the line
        System.out.println(nextLine[0] + nextLine[1] + "etc...");
    }
} catch (Exception e) {
    e.printStackTrace();
    Toast.makeText(this, "The specified file was not found", Toast.LENGTH_SHORT).show();
}

如果您想将.csv 文件与应用程序一起打包并在应用程序安装时将其安装在内部存储中,请在您的项目src/main 文件夹中创建一个assets 文件夹(例如,c:\myapp\app\src\main\assets\),并将.csv 文件放在那里,然后在您的活动中像这样引用它:

String csvfileString = this.getApplicationInfo().dataDir + File.separatorChar + "csvfile.csv"
File csvfile = new File(csvfileString);

【讨论】:

  • 感谢您的快速回复!我试过添加它,它似乎工作,除了我得到一个有趣的错误。 'new FileReader("strings.csv")' 出现错误“Unhandled Exception: java.io.FileNotFoundException”。这让我想到了两个问题。我的 strings.csv 文件在 android 项目文件中的什么位置?以及如何解决此错误?感谢您的帮助!
  • 再次感谢您提供更具体的信息。有时,当涉及到代码时,我不禁感到有点脱节。我仍然遇到同样的错误,但现在在不同的地方。我编辑了帖子的底部,添加了我根据您的帖子编辑的功能......我在这里做错了什么?
  • 我将在实际设备上运行它。但此时,我在编辑器本身(Android Studio)中遇到了错误。我的 strings.csv 文件确实位于该 app\src\main\assets\ 文件夹下。所以我不确定错误来自哪里......
  • @buradd 出了点问题。我收到此错误:Unresolved exception class when finding catch block: java.beans.IntrospectionException;;;;Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Ljava/beans/Introspector;
  • 看起来像 java.beans.Introspector 是一些 OpenCSV 类所必需的,是not included in android
【解决方案2】:

以下 sn-p 从 raw 资源文件夹中读取一个 CSV 文件(编译时将打包到您的 .apk 文件中)。

Android 默认不创建raw 文件夹。在您的项目中的res/raw 下创建一个原始文件夹并将您的 CSV 文件复制到其中。将 CSV 文件的名称保持小写,并在询问时将其转换为文本格式。我的 CSV 文件名为 welldata.csv

在 sn-p 中,WellData 是模型类(带有构造函数、getter 和 setter),wellDataList 是用于存储数据的ArrayList

private void readData() {
    InputStream is = getResources().openRawResource(R.raw.welldata);
    BufferedReader reader = new BufferedReader(
            new InputStreamReader(is, Charset.forName("UTF-8")));
    String line = "";

    try {
        while ((line = reader.readLine()) != null) {
           // Split the line into different tokens (using the comma as a separator).
            String[] tokens = line.split(",");

            // Read the data and store it in the WellData POJO.
            WellData wellData = new WellData();
            wellData.setOwner(tokens[0]);
            wellData.setApi(tokens[1]);
            wellData.setLongitude(tokens[2]);
            wellData.setLatitude(tokens[3]);
            wellData.setProperty(tokens[4]);
            wellData.setWellName(tokens[5]);
            wellDataList.add(wellData);

            Log.d("MainActivity" ,"Just Created " + wellData);
        }
    } catch (IOException e1) {
        Log.e("MainActivity", "Error" + line, e1);
        e1.printStackTrace();
    }
}

【讨论】:

    【解决方案3】:

    这在 Kotlin 中对我有用。您需要将 myfile.csv 文件放在 res/raw 文件夹中,如果不存在则创建该文件夹。

    val inputStream: InputStream = resources.openRawResource(R.raw.myfile)
    val reader = BufferedReader(InputStreamReader(inputStream, Charset.forName("UTF-8")))
    reader.readLines().forEach {
    
        //get a string array of all items in this line
        val items = it.split(",")
    
        //do what you want with each item
    }
    

    【讨论】:

      【解决方案4】:

      Android Studio 的新编码器。我一直在研究如何读取 CSV 文件,这最适合我的需要。 (s0、s1 等。字符串是在我的程序开始时定义的)。

          File fileDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
          File fileToGet = new File(fileDirectory,"aFileName.csv");
              try {
                  BufferedReader br = new BufferedReader(new FileReader(fileToGet));
                  String line;
                  while ((line = br.readLine()) !=null) {
                      String[] tokens = line.split(",");
                      s0=tokens[0].toString(); s1=tokens[1].toString(); s2=tokens[2].toString();
                      s3=tokens[3].toString(); s4=tokens[4].toString(); s5=tokens[5].toString();
                                                        }
                  }
          } catch (FileNotFoundException e) {
              e.printStackTrace();
          } catch (IOException e) {
              e.printStackTrace();
          }
      

      【讨论】:

      • 这个解决方案有点天真 - 它不会处理包含逗号值的列。 "first column", "column, with commma" 是包含 2 列的有效 CSV 行。
      • 你节省了我的时间。谢谢
      【解决方案5】:

      这是一个简单的方法,对我有用。

      MainActivity.java

      // Do not forget to call readWeatherData() in onCreate or wherever you need to :)
      
      // Defining ordered collection as WeatherSample class
      private List<WeatherSample> weatherSamples = new ArrayList<>();
      
      private void readWeatherData() {
          // Read the raw csv file
          InputStream is = getResources().openRawResource(R.raw.data);
      
          // Reads text from character-input stream, buffering characters for efficient reading
          BufferedReader reader = new BufferedReader(
                  new InputStreamReader(is, Charset.forName("UTF-8"))
          );
      
          // Initialization
          String line = "";
      
          // Initialization
          try {
              // Step over headers
              reader.readLine();
      
              // If buffer is not empty
              while ((line = reader.readLine()) != null) {
                  Log.d("MyActivity","Line: " + line);
                  // use comma as separator columns of CSV
                  String[] tokens = line.split(",");
                  // Read the data
                  WeatherSample sample = new WeatherSample();
      
                  // Setters
                  sample.setMonth(tokens[0]);
                  sample.setRainfall(Double.parseDouble(tokens[1]));
                  sample.setSumHours(Integer.parseInt(tokens[2]));
      
                  // Adding object to a class
                  weatherSamples.add(sample);
      
                  // Log the object
                  Log.d("My Activity", "Just created: " + sample);
              }
      
          } catch (IOException e) {
              // Logs error with priority level
              Log.wtf("MyActivity", "Error reading data file on line" + line, e);
      
              // Prints throwable details
              e.printStackTrace();
          }
      }
      

      WeatherSample.java

      public class WeatherSample {
      private String month;
      private double rainfall;
      private int sumHours;
      
      public String getMonth() {
          return month;
      }
      
      public void setMonth(String month) {
          this.month = month;
      }
      
      public double getRainfall() {
          return rainfall;
      }
      
      public void setRainfall(double rainfall) {
          this.rainfall = rainfall;
      }
      
      public int getSumHours() {
          return sumHours;
      }
      
      public void setSumHours(int sumHours) {
          this.sumHours = sumHours;
      }
      
      @Override
      public String toString() {
          return "WeatherSample{" +
                  "month='" + month + '\'' +
                  ", rainfall=" + rainfall +
                  ", sumHours=" + sumHours +
                  '}';
      }
      

      }

      至于您的源 CSV 文件,首先创建目录:
      app -> res (右键) -> New -> Android资源目录 -> 资源类型(raw) -> OK

      然后将您的 .csv 文件复制并粘贴到新出现的目录中:
      原始(右键单击)-> 在资源管理器中显示

      这是我用于项目的源文件:
      data.csv

      如果仍有错误,这里是完整项目的链接:
      Source Code

      希望对你有帮助,玩得开心:)

      【讨论】:

      • 欢迎来到 Stack Overflow!虽然链接是分享知识的好方法,但如果它们在未来被破坏,它们将无法真正回答问题。将回答问题的链接的基本内容添加到您的答案中。如果内容太复杂或太大而无法在此处放置,请描述所提出解决方案的总体思路。请记住始终保留指向原始解决方案网站的链接引用。见:How do I write a good answer?
      【解决方案6】:

      在文件夹 res/raw 中有一个名为 filename.csv 的文件:

         private void gettingItemsFromCSV() {
      
          BufferedInputStream bufferedInputStream = new BufferedInputStream(getResources().openRawResource(R.raw.filename));
          BufferedReader bufferedReader = new BufferedReader(
                  new InputStreamReader(bufferedInputStream));
      
          try {
              String line;
              while ((line = bufferedReader.readLine()) != null) {
                  Log.i("Test123", line);
              }
          } catch (Exception e) {
              e.printStackTrace();
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 2021-12-07
        • 1970-01-01
        • 2014-03-04
        • 2015-09-30
        • 2017-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-31
        相关资源
        最近更新 更多