下载目录下写问题
Issue writing in the Download directory
我正在尝试将此 xlsx 文件写入 Samsung Galaxy Tab A 2019 (Android 9.0) 的下载目录中。如果我尝试在我的模拟器(Google Pixel C with android 9.0)上执行此操作,它可以正常工作并且我可以看到该文件。如果我将应用程序提供给我的客户,它会给出一个错误,由这个函数赶上:
try {
importIntoExcel();
DynamicToast.makeSuccess(UserList.this, "Saved!", 2000).show();
b1.setEnabled(true);
} catch (IOException e) {
DynamicToast.makeError(UserList.this, "Error!", 2000).show();
e.printStackTrace();
}
不幸的是,我无法看到堆栈跟踪,因为我无法将客户端的平板电脑连接到我的 PC。这是行不通的方法:
private void importIntoExcel() throws IOException {
String[] columns = {"Numero Test", "Codice ID", "Genere", "Data di nascita", "Protocollo", "Data del test", " ", "Cornice", "Nome cornice", "Fluidità", "Flessibilità",
"Originalita'", "Elaborazione'", "Titolo", "Tempo Reazione", "Tempo Completamento", "Numero cancellature", "Numero Undo"};
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("RiepilogoTest");
Font headerFont = workbook.createFont();
headerFont.setBold(true);
headerFont.setFontHeightInPoints((short) 14);
headerFont.setColor(IndexedColors.RED.getIndex());
CellStyle headerCellStyle = workbook.createCellStyle();
headerCellStyle.setFont(headerFont);
headerCellStyle.setAlignment(HorizontalAlignment.CENTER_SELECTION);
// Create a Row
Row headerRow = sheet.createRow(0);
for (int i = 0; i < columns.length; i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(columns[i]);
cell.setCellStyle(headerCellStyle);
}
// Create Other rows and cells with contacts data
int rowNum = 1;
//Inserting the data
File dir = new File("/data/user/0/com.example.williamstest/");
for (File file : dir.listFiles()) {
if (file.getName().startsWith("app_draw")) {
String typeTest = file.getName().replaceAll("[^\d.]", "");
if (new File(file.getAbsolutePath() + "/infotest.txt").exists()) {
FileReader f = new FileReader(file.getAbsolutePath() + "/infotest.txt");
LineNumberReader reader = new LineNumberReader(f);
String line;
String protocollo = "";
line = reader.readLine();
Row row = null;
if (line.equals(userLogged)) {
row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue("Test: " + typeTest);
line = reader.readLine();
row.createCell(2).setCellValue(line);
line = reader.readLine();
if (line.equals("0")) row.createCell(2).setCellValue("/");
row.createCell(3).setCellValue(line);
line = reader.readLine();
protocollo = line;
row.createCell(4).setCellValue(line);
line = reader.readLine();
row.createCell(5).setCellValue(line);
line = reader.readLine();
row.createCell(1).setCellValue(line);
}
for (int i=0; i<12; i++) {
String content = "";
reader = new LineNumberReader(new FileReader(file.getAbsolutePath() + "/" + protocollo + (i + 1) + "_score.txt"));
while ((line = reader.readLine()) != null) {
content+=line+"\n";
}
String[] values = content.split("\n");
row.createCell(6).setCellValue(" "); //Vuota
row.createCell(7).setCellValue(i+1); //Cornice
row.createCell(8).setCellValue(values[4]); //Nome cornice
row.createCell(9).setCellValue(values[0]); //Fluidita
row.createCell(10).setCellValue(values[1]); //Flessibilita
row.createCell(11).setCellValue(values[2]); //Originalita'
row.createCell(12).setCellValue(values[3]); //Elaborazione
row.createCell(13).setCellValue(values[9]); //Titolo
row.createCell(14).setCellValue(values[5]); //Tempo reazione
row.createCell(15).setCellValue(values[6]); //Tempo Completamento
row.createCell(16).setCellValue(values[7]); //Numero cancellature
row.createCell(17).setCellValue(values[8]); //Numero undo
row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(" ");
row.createCell(1).setCellValue(" ");
row.createCell(2).setCellValue(" ");
row.createCell(3).setCellValue(" ");
row.createCell(4).setCellValue(" ");
row.createCell(5).setCellValue(" ");
}
f.close();
}
}
}
sheet.setDefaultColumnWidth(23);
// Write the output to a file
if (new File(Environment.getExternalStorageDirectory(), "Download/risultatiTest.xlsx").exists())
new File(Environment.getExternalStorageDirectory(), "Download/risultatiTest.xlsx").delete();
FileOutputStream fileOut = new FileOutputStream(new File(Environment.getExternalStorageDirectory(), "Download/risultatiTest.xlsx"));
workbook.write(fileOut);
fileOut.close();
}
我也写了这个保存在同一个目录下的方法,而且可以用,所以我认为这不是权限问题:
private void generateImages() throws IOException {
File dir = new File("/data/user/0/com.example.williamstest/");
File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), "/Download/ImmaginiTest");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs())
Log.d("App", "failed to create directory");
} else {
if (mediaStorageDir.isDirectory()) {
for (File child : mediaStorageDir.listFiles())
deleteRecursive(child);
}
mediaStorageDir.delete();
mediaStorageDir.mkdirs();
}
for (File file : dir.listFiles()) {
if (file.getName().startsWith("app_draw") && Character.isDigit(file.getName().charAt(file.getName().length() - 1))) {
File makingDir = new File(Environment.getExternalStorageDirectory(), "/Download/ImmaginiTest/Test"+file.getName().substring(file.getName().length() - 1));
makingDir.mkdirs();
for (File fileS : file.listFiles()) {
if (fileS.getName().endsWith(".png")) {
Bitmap b = BitmapFactory.decodeStream(new FileInputStream(fileS));
File mypath=new File(makingDir, fileS.getName());
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
b.compress(Bitmap.CompressFormat.PNG, 100, fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
}
您有任何 logcat 可以用来缩小错误来源的范围吗?
你也可以从避免使用这样的魔术字符串开始:
File dir = new File("/data/user/0/com.example.williamstest/");
File makingDir = new File(Environment.getExternalStorageDirectory(), "/Download/ImmaginiTest/Test"+file.getName().substring(file.getName().length() - 1));
从 API 开始,29 Environment.getExternalStoragePublicDirectory()
已弃用。请看这个 AndroidStudio getExternalStoragePublicDirectory in API 29。
传统上,外部存储通常是 SD 卡,但也可以实现为内置存储。
因此有必要验证您是否有 并且 在访问文件之前是否安装了
Environment.getExternalStorageDirectory()
。否则,您需要一个内部目录作为后备。查看文档 here 了解如何操作。
此外,如果您的目标是 API 级别 29,请确保您也在清单的 application
标签上使用 android:requestLegacyExternalStorage="true"
。看看 here.
在某些设备和较新的 Android 版本中,Environment.getExternalStorageDirectory()
不再是 return 有效路径。尝试使用 Context.getExternalFilesDir(null)
代替,
它应该 return 这个路径:/storage/emulated/0/Android/data/your.package.name/
。试试看是否是问题所在。这是 doc.
我建议您模拟一些类似的三星设备,看看是否可以重现错误以查看 logcat 输出
可能是电脑和android设备上写入的文件不一样。新的 android 版本阻止应用程序访问某些文件夹。因此,请尝试将其写入不同的文件夹。
也许不要创建新文件夹并将其写入现有文件夹。
也有人说Environment.getExternalStorageDirectory()
已弃用,您不应在较新的 android 版本上使用它,但您仍然可以在较旧的版本上使用它。
另外你不能 100% 信任模拟器,因为它不是 100% 相同
我正在尝试将此 xlsx 文件写入 Samsung Galaxy Tab A 2019 (Android 9.0) 的下载目录中。如果我尝试在我的模拟器(Google Pixel C with android 9.0)上执行此操作,它可以正常工作并且我可以看到该文件。如果我将应用程序提供给我的客户,它会给出一个错误,由这个函数赶上:
try {
importIntoExcel();
DynamicToast.makeSuccess(UserList.this, "Saved!", 2000).show();
b1.setEnabled(true);
} catch (IOException e) {
DynamicToast.makeError(UserList.this, "Error!", 2000).show();
e.printStackTrace();
}
不幸的是,我无法看到堆栈跟踪,因为我无法将客户端的平板电脑连接到我的 PC。这是行不通的方法:
private void importIntoExcel() throws IOException {
String[] columns = {"Numero Test", "Codice ID", "Genere", "Data di nascita", "Protocollo", "Data del test", " ", "Cornice", "Nome cornice", "Fluidità", "Flessibilità",
"Originalita'", "Elaborazione'", "Titolo", "Tempo Reazione", "Tempo Completamento", "Numero cancellature", "Numero Undo"};
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("RiepilogoTest");
Font headerFont = workbook.createFont();
headerFont.setBold(true);
headerFont.setFontHeightInPoints((short) 14);
headerFont.setColor(IndexedColors.RED.getIndex());
CellStyle headerCellStyle = workbook.createCellStyle();
headerCellStyle.setFont(headerFont);
headerCellStyle.setAlignment(HorizontalAlignment.CENTER_SELECTION);
// Create a Row
Row headerRow = sheet.createRow(0);
for (int i = 0; i < columns.length; i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(columns[i]);
cell.setCellStyle(headerCellStyle);
}
// Create Other rows and cells with contacts data
int rowNum = 1;
//Inserting the data
File dir = new File("/data/user/0/com.example.williamstest/");
for (File file : dir.listFiles()) {
if (file.getName().startsWith("app_draw")) {
String typeTest = file.getName().replaceAll("[^\d.]", "");
if (new File(file.getAbsolutePath() + "/infotest.txt").exists()) {
FileReader f = new FileReader(file.getAbsolutePath() + "/infotest.txt");
LineNumberReader reader = new LineNumberReader(f);
String line;
String protocollo = "";
line = reader.readLine();
Row row = null;
if (line.equals(userLogged)) {
row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue("Test: " + typeTest);
line = reader.readLine();
row.createCell(2).setCellValue(line);
line = reader.readLine();
if (line.equals("0")) row.createCell(2).setCellValue("/");
row.createCell(3).setCellValue(line);
line = reader.readLine();
protocollo = line;
row.createCell(4).setCellValue(line);
line = reader.readLine();
row.createCell(5).setCellValue(line);
line = reader.readLine();
row.createCell(1).setCellValue(line);
}
for (int i=0; i<12; i++) {
String content = "";
reader = new LineNumberReader(new FileReader(file.getAbsolutePath() + "/" + protocollo + (i + 1) + "_score.txt"));
while ((line = reader.readLine()) != null) {
content+=line+"\n";
}
String[] values = content.split("\n");
row.createCell(6).setCellValue(" "); //Vuota
row.createCell(7).setCellValue(i+1); //Cornice
row.createCell(8).setCellValue(values[4]); //Nome cornice
row.createCell(9).setCellValue(values[0]); //Fluidita
row.createCell(10).setCellValue(values[1]); //Flessibilita
row.createCell(11).setCellValue(values[2]); //Originalita'
row.createCell(12).setCellValue(values[3]); //Elaborazione
row.createCell(13).setCellValue(values[9]); //Titolo
row.createCell(14).setCellValue(values[5]); //Tempo reazione
row.createCell(15).setCellValue(values[6]); //Tempo Completamento
row.createCell(16).setCellValue(values[7]); //Numero cancellature
row.createCell(17).setCellValue(values[8]); //Numero undo
row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(" ");
row.createCell(1).setCellValue(" ");
row.createCell(2).setCellValue(" ");
row.createCell(3).setCellValue(" ");
row.createCell(4).setCellValue(" ");
row.createCell(5).setCellValue(" ");
}
f.close();
}
}
}
sheet.setDefaultColumnWidth(23);
// Write the output to a file
if (new File(Environment.getExternalStorageDirectory(), "Download/risultatiTest.xlsx").exists())
new File(Environment.getExternalStorageDirectory(), "Download/risultatiTest.xlsx").delete();
FileOutputStream fileOut = new FileOutputStream(new File(Environment.getExternalStorageDirectory(), "Download/risultatiTest.xlsx"));
workbook.write(fileOut);
fileOut.close();
}
我也写了这个保存在同一个目录下的方法,而且可以用,所以我认为这不是权限问题:
private void generateImages() throws IOException {
File dir = new File("/data/user/0/com.example.williamstest/");
File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), "/Download/ImmaginiTest");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs())
Log.d("App", "failed to create directory");
} else {
if (mediaStorageDir.isDirectory()) {
for (File child : mediaStorageDir.listFiles())
deleteRecursive(child);
}
mediaStorageDir.delete();
mediaStorageDir.mkdirs();
}
for (File file : dir.listFiles()) {
if (file.getName().startsWith("app_draw") && Character.isDigit(file.getName().charAt(file.getName().length() - 1))) {
File makingDir = new File(Environment.getExternalStorageDirectory(), "/Download/ImmaginiTest/Test"+file.getName().substring(file.getName().length() - 1));
makingDir.mkdirs();
for (File fileS : file.listFiles()) {
if (fileS.getName().endsWith(".png")) {
Bitmap b = BitmapFactory.decodeStream(new FileInputStream(fileS));
File mypath=new File(makingDir, fileS.getName());
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
b.compress(Bitmap.CompressFormat.PNG, 100, fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
}
您有任何 logcat 可以用来缩小错误来源的范围吗?
你也可以从避免使用这样的魔术字符串开始:
File dir = new File("/data/user/0/com.example.williamstest/");
File makingDir = new File(Environment.getExternalStorageDirectory(), "/Download/ImmaginiTest/Test"+file.getName().substring(file.getName().length() - 1));
从 API 开始,29 Environment.getExternalStoragePublicDirectory()
已弃用。请看这个 AndroidStudio getExternalStoragePublicDirectory in API 29。
传统上,外部存储通常是 SD 卡,但也可以实现为内置存储。
因此有必要验证您是否有 并且 在访问文件之前是否安装了
Environment.getExternalStorageDirectory()
。否则,您需要一个内部目录作为后备。查看文档 here 了解如何操作。
此外,如果您的目标是 API 级别 29,请确保您也在清单的 application
标签上使用 android:requestLegacyExternalStorage="true"
。看看 here.
在某些设备和较新的 Android 版本中,Environment.getExternalStorageDirectory()
不再是 return 有效路径。尝试使用 Context.getExternalFilesDir(null)
代替,
它应该 return 这个路径:/storage/emulated/0/Android/data/your.package.name/
。试试看是否是问题所在。这是 doc.
我建议您模拟一些类似的三星设备,看看是否可以重现错误以查看 logcat 输出
可能是电脑和android设备上写入的文件不一样。新的 android 版本阻止应用程序访问某些文件夹。因此,请尝试将其写入不同的文件夹。 也许不要创建新文件夹并将其写入现有文件夹。
也有人说Environment.getExternalStorageDirectory()
已弃用,您不应在较新的 android 版本上使用它,但您仍然可以在较旧的版本上使用它。
另外你不能 100% 信任模拟器,因为它不是 100% 相同