@@ -13,8 +13,10 @@ import org.apache.poi.ss.usermodel.Sheet
1313import  org.apache.poi.ss.usermodel.Workbook 
1414import  org.apache.poi.ss.usermodel.WorkbookFactory 
1515import  org.apache.poi.ss.util.CellReference 
16+ import  org.apache.poi.util.DefaultTempFileCreationStrategy 
1617import  org.apache.poi.util.LocaleUtil 
1718import  org.apache.poi.util.LocaleUtil.getUserTimeZone 
19+ import  org.apache.poi.util.TempFile 
1820import  org.apache.poi.xssf.usermodel.XSSFWorkbook 
1921import  org.jetbrains.kotlinx.dataframe.AnyFrame 
2022import  org.jetbrains.kotlinx.dataframe.AnyRow 
@@ -31,6 +33,7 @@ import java.io.File
3133import  java.io.InputStream 
3234import  java.io.OutputStream 
3335import  java.net.URL 
36+ import  java.nio.file.Files 
3437import  java.time.LocalDate 
3538import  java.time.LocalDateTime 
3639import  java.util.Calendar 
@@ -55,6 +58,27 @@ public class Excel : SupportedDataFrameFormat {
5558internal  class  DefaultReadExcelMethod (path :  String? ) : AbstractDefaultReadMethod(path, MethodArguments .EMPTY , readExcel)
5659
5760private  const  val  readExcel =  " readExcel" 
61+ private  const  val  readExcelTempFolderPrefix =  " dataframe-excel" 
62+ 
63+ /* *
64+  * To prevent [Issue #402](https://github.com/Kotlin/dataframe/issues/402): 
65+  * 
66+  * Creates new temp directory instead of the default `/tmp/poifiles` which would 
67+  * cause permission issues for multiple users. 
68+  */  
69+ private  fun  setWorkbookTempDirectory () {
70+  val  tempDir =  try  {
71+  Files .createTempDirectory(readExcelTempFolderPrefix)
72+  .toFile()
73+  .also  { it.deleteOnExit() }
74+  } catch  (e:  Exception ) {
75+  //  Ignore, let WorkbookFactory use the default temp directory instead
76+  return 
77+  }
78+  TempFile .setTempFileCreationStrategy(
79+  DefaultTempFileCreationStrategy (tempDir)
80+  )
81+ }
5882
5983/* *
6084 * @param sheetName sheet to read. By default, the first sheet in the document 
@@ -72,6 +96,7 @@ public fun DataFrame.Companion.readExcel(
7296 rowsCount :  Int?  = null,
7397 nameRepairStrategy :  NameRepairStrategy  = NameRepairStrategy .CHECK_UNIQUE ,
7498): AnyFrame  {
99+  setWorkbookTempDirectory()
75100 val  wb =  WorkbookFactory .create(url.openStream())
76101 return  wb.use { readExcel(wb, sheetName, skipRows, columns, rowsCount, nameRepairStrategy) }
77102}
@@ -92,6 +117,7 @@ public fun DataFrame.Companion.readExcel(
92117 rowsCount :  Int?  = null,
93118 nameRepairStrategy :  NameRepairStrategy  = NameRepairStrategy .CHECK_UNIQUE ,
94119): AnyFrame  {
120+  setWorkbookTempDirectory()
95121 val  wb =  WorkbookFactory .create(file)
96122 return  wb.use { readExcel(it, sheetName, skipRows, columns, rowsCount, nameRepairStrategy) }
97123}
@@ -129,6 +155,7 @@ public fun DataFrame.Companion.readExcel(
129155 rowsCount :  Int?  = null,
130156 nameRepairStrategy :  NameRepairStrategy  = NameRepairStrategy .CHECK_UNIQUE ,
131157): AnyFrame  {
158+  setWorkbookTempDirectory()
132159 val  wb =  WorkbookFactory .create(inputStream)
133160 return  wb.use { readExcel(it, sheetName, skipRows, columns, rowsCount, nameRepairStrategy) }
134161}
@@ -206,7 +233,8 @@ public fun DataFrame.Companion.readExcel(
206233 }
207234
208235 val  name =  repairNameIfRequired(nameFromCell, columnNameCounters, nameRepairStrategy)
209-  columnNameCounters[nameFromCell] =  columnNameCounters.getOrDefault(nameFromCell, 0 ) +  1  //  increase the counter for specific column name
236+  columnNameCounters[nameFromCell] = 
237+  columnNameCounters.getOrDefault(nameFromCell, 0 ) +  1  //  increase the counter for specific column name
210238
211239 val  values:  List <Any ?> =  valueRowsRange.map {
212240 val  row:  Row ?  =  sheet.getRow(it)
@@ -225,10 +253,17 @@ public fun DataFrame.Companion.readExcel(
225253 * 
226254 * TODO: https://github.com/Kotlin/dataframe/issues/387 
227255 */  
228- private  fun  repairNameIfRequired (nameFromCell :  String , columnNameCounters :  MutableMap <String , Int >, nameRepairStrategy :  NameRepairStrategy ): String  {
256+ private  fun  repairNameIfRequired (
257+  nameFromCell :  String ,
258+  columnNameCounters :  MutableMap <String , Int >,
259+  nameRepairStrategy :  NameRepairStrategy ,
260+ ): String  {
229261 return  when  (nameRepairStrategy) {
230262 NameRepairStrategy .DO_NOTHING  ->  nameFromCell
231-  NameRepairStrategy .CHECK_UNIQUE  ->  if  (columnNameCounters.contains(nameFromCell)) throw  DuplicateColumnNamesException (columnNameCounters.keys.toList()) else  nameFromCell
263+  NameRepairStrategy .CHECK_UNIQUE  ->  if  (columnNameCounters.contains(nameFromCell)) throw  DuplicateColumnNamesException (
264+  columnNameCounters.keys.toList()
265+  ) else  nameFromCell
266+ 
232267 NameRepairStrategy .MAKE_UNIQUE  ->  if  (nameFromCell.isEmpty()) { //  probably it's never empty because of filling empty column names earlier
233268 val  emptyName =  " Unknown column" 
234269 if  (columnNameCounters.contains(emptyName)) " ${emptyName}${columnNameCounters[emptyName]} " 
0 commit comments